refactor: make linter happy

also add a few unused coprocessor instructions

Signed-off-by: Amneesh Singh <natto@weirdnatto.in>
This commit is contained in:
2023-09-14 01:07:41 +05:30
parent 387f3c8f07
commit 3cf5cbd024
19 changed files with 394 additions and 240 deletions

View File

@@ -7,10 +7,10 @@
using namespace logger;
Cpu::Cpu(Bus& bus)
: gpr(0)
: bus(std::make_shared<Bus>(bus))
, gpr({ 0 })
, cpsr(0)
, spsr(0)
, bus(std::make_shared<Bus>(bus))
, gpr_banked({ { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 } })
, spsr_banked({ 0, 0, 0, 0, 0 }) {
cpsr.set_mode(Mode::System);
@@ -18,20 +18,25 @@ Cpu::Cpu(Bus& bus)
cpsr.set_fiq_disabled(true);
cpsr.set_state(State::Arm);
log_info("CPU successfully initialised");
// PC is always two instructions ahead in the pipeline
pc += 2 * ARM_INSTRUCTION_SIZE;
}
/* change modes */
void
Cpu::chg_mode(Mode from, Mode to) {
Cpu::chg_mode(const Mode to) {
Mode from = cpsr.mode();
if (from == to)
return;
/* TODO: replace visible registers with view once I understand how to
* concatenate views */
#define STORE_BANKED(mode, MODE) \
std::copy(gpr + GPR_##MODE##_BANKED_FIRST, \
gpr + GPR_##MODE##_BANKED_FIRST + GPR_##MODE##_BANKED_COUNT, \
gpr_banked.mode)
std::copy(gpr.begin() + GPR_##MODE##_FIRST, \
gpr.begin() + GPR_COUNT - 1, \
gpr_banked.mode.begin())
switch (from) {
case Mode::Fiq:
@@ -66,9 +71,9 @@ Cpu::chg_mode(Mode from, Mode to) {
}
#define RESTORE_BANKED(mode, MODE) \
std::copy(gpr_banked.mode, \
gpr_banked.mode + GPR_##MODE##_BANKED_COUNT, \
gpr + GPR_##MODE##_BANKED_FIRST)
std::copy(gpr_banked.mode.begin(), \
gpr_banked.mode.end(), \
gpr.begin() + GPR_##MODE##_FIRST)
switch (to) {
case Mode::Fiq:
@@ -109,11 +114,15 @@ Cpu::chg_mode(Mode from, Mode to) {
void
Cpu::step() {
uint32_t insn = 0xffffffff;
uint32_t cur_pc = pc - 2 * ARM_INSTRUCTION_SIZE;
if (cpsr.state() == State::Arm) {
std::string disassembled = exec_arm(insn);
log_info("{:#010X} : {}", gpr[15], disassembled);
gpr[15] += ARM_INSTRUCTION_SIZE;
log_info("{:#034b}", bus->read_word(cur_pc));
std::string disassembled = exec_arm(bus->read_word(cur_pc));
log_info("{:#010X} : {}", cur_pc, disassembled);
pc += ARM_INSTRUCTION_SIZE;
}
}

View File

@@ -13,40 +13,32 @@ class Cpu {
void step();
private:
static constexpr size_t GPR_FIQ_BANKED_FIRST = 8;
static constexpr size_t GPR_FIQ_BANKED_COUNT = 7;
static constexpr size_t GPR_COUNT = 16;
static constexpr size_t GPR_SVC_BANKED_FIRST = 13;
static constexpr size_t GPR_SVC_BANKED_COUNT = 2;
static constexpr size_t GPR_FIQ_FIRST = 8;
static constexpr size_t GPR_SVC_FIRST = 13;
static constexpr size_t GPR_ABT_FIRST = 13;
static constexpr size_t GPR_IRQ_FIRST = 13;
static constexpr size_t GPR_UND_FIRST = 13;
static constexpr size_t GPR_SYS_USR_FIRST = 8;
static constexpr size_t GPR_ABT_BANKED_FIRST = 13;
static constexpr size_t GPR_ABT_BANKED_COUNT = 2;
static constexpr size_t GPR_IRQ_BANKED_FIRST = 13;
static constexpr size_t GPR_IRQ_BANKED_COUNT = 2;
static constexpr size_t GPR_UND_BANKED_FIRST = 13;
static constexpr size_t GPR_UND_BANKED_COUNT = 2;
static constexpr size_t GPR_SYS_USR_BANKED_FIRST = 8;
static constexpr size_t GPR_SYS_USR_BANKED_COUNT = 7;
static constexpr size_t GPR_VISIBLE_COUNT = 16;
uint32_t gpr[GPR_VISIBLE_COUNT]; // general purpose registers
Psr cpsr; // current program status register
Psr spsr; // status program status register
std::shared_ptr<Bus> bus;
std::array<uint32_t, GPR_COUNT> gpr; // general purpose registers
Psr cpsr; // current program status register
Psr spsr; // status program status register
uint32_t& pc = gpr[15];
struct {
uint32_t fiq[GPR_FIQ_BANKED_COUNT];
uint32_t svc[GPR_SVC_BANKED_COUNT];
uint32_t abt[GPR_ABT_BANKED_COUNT];
uint32_t irq[GPR_IRQ_BANKED_COUNT];
uint32_t und[GPR_UND_BANKED_COUNT];
std::array<uint32_t, GPR_COUNT - GPR_FIQ_FIRST - 1> fiq;
std::array<uint32_t, GPR_COUNT - GPR_SVC_FIRST - 1> svc;
std::array<uint32_t, GPR_COUNT - GPR_ABT_FIRST - 1> abt;
std::array<uint32_t, GPR_COUNT - GPR_IRQ_FIRST - 1> irq;
std::array<uint32_t, GPR_COUNT - GPR_UND_FIRST - 1> und;
// visible registers before the mode switch
uint32_t old[GPR_SYS_USR_BANKED_COUNT];
std::array<uint32_t, GPR_COUNT - GPR_SYS_USR_FIRST> old;
} gpr_banked; // banked general purpose registers
struct {
@@ -57,6 +49,6 @@ class Cpu {
Psr und;
} spsr_banked; // banked saved program status registers
void chg_mode(Mode from, Mode to);
std::string exec_arm(uint32_t insn);
void chg_mode(const Mode to);
std::string exec_arm(const uint32_t insn);
};

View File

@@ -5,25 +5,27 @@
#include <cstdint>
using namespace logger;
using std::array;
using stringv = std::string_view;
std::string
Cpu::exec_arm(uint32_t insn) {
Cpu::exec_arm(const uint32_t insn) {
Condition cond = static_cast<Condition>(get_bit_range(insn, 28, 31));
std::string disassembled;
auto pc_error = [](uint8_t r, const char* syn) {
auto pc_error = [](uint8_t r, stringv syn) {
if (r == 15)
log_error("Using PC (R15) as operand in {}", syn);
};
auto pc_undefined = [](uint8_t r, const char* syn) {
auto pc_undefined = [](uint8_t r, stringv syn) {
if (r == 15)
log_warn("Using PC (R15) as operand in {}", syn);
};
// Branch and exhcange
if ((insn & 0x0FFFFFF0) == 0x012FFF10) {
static constexpr char syn[] = "BX";
static constexpr stringv syn = "BX";
uint8_t rn = insn & 0b1111;
@@ -38,16 +40,16 @@ Cpu::exec_arm(uint32_t insn) {
cpsr.set_state(state);
// copy to PC
gpr[15] = gpr[rn];
pc = gpr[rn];
// ignore [1:0] bits for arm and 0 bit for thumb
rst_nth_bit(gpr[15], 0);
rst_nth_bit(pc, 0);
if (state == State::Arm)
rst_nth_bit(gpr[15], 1);
rst_nth_bit(pc, 1);
}
// Branch
} else if ((insn & 0x0E000000) == 0x0A000000) {
static constexpr char syn[] = "B";
static constexpr stringv syn = "B";
bool link = get_nth_bit(insn, 24);
uint32_t offset = get_bit_range(insn, 0, 23);
@@ -63,14 +65,14 @@ Cpu::exec_arm(uint32_t insn) {
offset |= 0xFC000000;
if (link)
gpr[14] = gpr[15] - ARM_INSTRUCTION_SIZE;
gpr[14] = pc - ARM_INSTRUCTION_SIZE;
gpr[15] += offset;
pc += offset - ARM_INSTRUCTION_SIZE;
}
// Multiply
} else if ((insn & 0x0FC000F0) == 0x00000090) {
static constexpr char syn[2][4] = { "MUL", "MLA" };
static constexpr array<stringv, 2> syn = { "MUL", "MLA" };
uint8_t rm = get_bit_range(insn, 0, 3);
uint8_t rs = get_bit_range(insn, 8, 11);
@@ -117,8 +119,9 @@ Cpu::exec_arm(uint32_t insn) {
}
// Multiply long
} else if ((insn & 0x0F8000F0) == 0x00800090) {
static constexpr char syn[2][2][6] = { { "SMULL", "SMLAL" },
{ "UMULL", "UMLAL" } };
static constexpr array<array<stringv, 2>, 2> syn = {
{ { "SMULL", "SMLAL" }, { "UMULL", "UMLAL" } }
};
uint8_t rm = get_bit_range(insn, 0, 3);
uint8_t rs = get_bit_range(insn, 8, 11);
@@ -157,7 +160,7 @@ Cpu::exec_arm(uint32_t insn) {
gpr[rdhi] = get_bit_range(eval, 32, 63);
} else {
int64_t eval = static_cast<uint64_t>(gpr[rm]) *
int64_t eval = static_cast<int64_t>(gpr[rm]) *
static_cast<int64_t>(gpr[rs]) +
(a ? static_cast<int64_t>(gpr[rdhi]) << 32 |
static_cast<int64_t>(gpr[rdlo])
@@ -178,7 +181,7 @@ Cpu::exec_arm(uint32_t insn) {
// Single data swap
} else if ((insn & 0x0FB00FF0) == 0x01000090) {
static constexpr char syn[] = "SWP";
static constexpr stringv syn = "SWP";
uint8_t rm = get_bit_range(insn, 0, 3);
uint8_t rd = get_bit_range(insn, 12, 15);
@@ -206,32 +209,32 @@ Cpu::exec_arm(uint32_t insn) {
// TODO: create abstraction to reuse for block data and single data
// transfer
} else if ((insn & 0x0E000090) == 0x00000090) {
static constexpr char syn[2][4] = { "STR", "LDR" };
static constexpr array<stringv, 2> syn_ = { "STR", "LDR" };
uint8_t rm = get_bit_range(insn, 0, 3);
uint8_t h = get_nth_bit(insn, 5);
uint8_t s = get_nth_bit(insn, 6);
uint8_t rd = get_bit_range(insn, 12, 15);
uint8_t rn = get_bit_range(insn, 16, 19);
bool l = get_nth_bit(insn, 20);
bool w = get_nth_bit(insn, 21);
bool imm = get_nth_bit(insn, 22);
bool u = get_nth_bit(insn, 23);
bool p = get_nth_bit(insn, 24);
uint32_t offset;
uint8_t rm = get_bit_range(insn, 0, 3);
uint8_t h = get_nth_bit(insn, 5);
uint8_t s = get_nth_bit(insn, 6);
uint8_t rd = get_bit_range(insn, 12, 15);
uint8_t rn = get_bit_range(insn, 16, 19);
bool l = get_nth_bit(insn, 20);
bool w = get_nth_bit(insn, 21);
bool imm = get_nth_bit(insn, 22);
bool u = get_nth_bit(insn, 23);
bool p = get_nth_bit(insn, 24);
uint32_t offset = 0;
std::string syn =
fmt::format("{}{}{}", syn_[l], (s ? "S" : ""), (h ? 'H' : 'B'));
if (!p && w)
log_error("Write-back enabled with post-indexing in {}", syn[l]);
log_error("Write-back enabled with post-indexing in {}", syn);
if (s && !l)
log_error("Signed data found in {}", syn[l]);
log_error("Signed data found in {}", syn);
if (w)
pc_error(rn, syn[l]);
pc_error(rm, syn[l]);
if (rd == 15 && !l && s && h)
;
pc_error(rn, syn);
pc_error(rm, syn);
{
offset = (imm ? get_bit_range(insn, 8, 11) << 4 | rm : gpr[rm]);
@@ -241,8 +244,8 @@ Cpu::exec_arm(uint32_t insn) {
(imm ? offset : rm));
disassembled = fmt::format(
"{}{}{}{} R{:d}{}",
syn[l],
"{}{}{}{} R{:d},{}",
syn_[l],
cond,
(s ? "S" : ""),
(h ? 'H' : 'B'),
@@ -254,7 +257,10 @@ Cpu::exec_arm(uint32_t insn) {
}
if (cpsr.condition(cond)) {
uint32_t address = (u ? gpr[rn] + offset : gpr[rn] - offset);
uint32_t address = gpr[rn];
if (p)
address += (u ? offset : -offset);
// load
if (l) {
@@ -287,7 +293,92 @@ Cpu::exec_arm(uint32_t insn) {
bus->write_halfword(address, gpr[rd]);
}
}
if (!p)
address += (u ? offset : -offset);
if (!p || w)
gpr[rn] = address;
}
// Software Interrupt
// What to do here?
} else if ((insn & 0x0F000000) == 0x0F000000) {
static constexpr stringv syn = "SWI";
if (cpsr.condition(cond)) {
chg_mode(Mode::Supervisor);
pc = 0x08;
spsr = cpsr;
}
disassembled = fmt::format("{}{} 0", syn, cond);
// Coprocessor data transfer
} else if ((insn & 0x0E000000) == 0x0C000000) {
static constexpr array<stringv, 2> syn = { "STC", "LDC" };
[[maybe_unused]] uint8_t offset = get_bit_range(insn, 0, 7);
uint8_t cpn = get_bit_range(insn, 8, 11);
uint8_t crd = get_bit_range(insn, 12, 15);
[[maybe_unused]] uint8_t rn = get_bit_range(insn, 16, 19);
bool l = get_nth_bit(insn, 20);
[[maybe_unused]] bool w = get_nth_bit(insn, 21);
bool n = get_nth_bit(insn, 22);
[[maybe_unused]] bool u = get_nth_bit(insn, 23);
[[maybe_unused]] bool p = get_nth_bit(insn, 24);
disassembled = fmt::format(
"{}{}{} p{},c{},{}", syn[l], cond, (n ? "L" : ""), cpn, crd, "a.");
log_error("Unimplemented instruction: {}", syn[l]);
// Coprocessor data operation
} else if ((insn & 0x0F000010) == 0x0E000000) {
static constexpr stringv syn = "CDP";
uint8_t crm = get_bit_range(insn, 0, 4);
uint8_t cp = get_bit_range(insn, 5, 7);
uint8_t cpn = get_bit_range(insn, 8, 11);
uint8_t crd = get_bit_range(insn, 12, 15);
uint8_t crn = get_bit_range(insn, 16, 19);
uint8_t cp_opc = get_bit_range(insn, 20, 23);
disassembled = fmt::format("{}{} p{},{},c{},c{},c{},{}",
syn,
cond,
cpn,
cp_opc,
crd,
crn,
crm,
cp);
log_error("Unimplemented instruction: {}", syn);
// Coprocessor register transfer
} else if ((insn & 0x0F000010) == 0x0E000010) {
static constexpr array<stringv, 2> syn = { "MCR", "MRC" };
uint8_t crm = get_bit_range(insn, 0, 4);
uint8_t cp = get_bit_range(insn, 5, 7);
uint8_t cpn = get_bit_range(insn, 8, 11);
uint8_t rd = get_bit_range(insn, 12, 15);
uint8_t crn = get_bit_range(insn, 16, 19);
bool l = get_nth_bit(insn, 20);
uint8_t cp_opc = get_bit_range(insn, 21, 23);
disassembled = fmt::format("{}{} p{},{},c{},c{},c{},{}",
syn[l],
cond,
cpn,
cp_opc,
rd,
crn,
crm,
cp);
log_error("Unimplemented instruction: {}", syn[l]);
}
return disassembled;

View File

@@ -2,9 +2,8 @@
#include "util/bits.hh"
#include "util/log.hh"
Psr::Psr(uint32_t raw) {
psr = raw & PSR_CLEAR_RESERVED;
}
Psr::Psr(uint32_t raw)
: psr(raw & PSR_CLEAR_RESERVED) {}
Mode
Psr::mode() const {

View File

@@ -32,3 +32,23 @@ operator<<(std::ostream& os, const Condition cond) {
return os;
}
std::ostream&
operator<<(std::ostream& os, const ShiftType shift_type) {
#define CASE(type) \
case ShiftType::type: \
os << #type; \
break;
switch (shift_type) {
CASE(LSL)
CASE(LSR)
CASE(ASR)
CASE(ROR)
}
#undef CASE
return os;
}

View File

@@ -40,6 +40,12 @@ enum class Condition {
AL = 0b1110
};
// https://fmt.dev/dev/api.html#std-ostream-support
std::ostream&
operator<<(std::ostream& os, const Condition cond);
template<>
struct fmt::formatter<Condition> : ostream_formatter {};
enum class OpCode {
AND = 0b0000,
EOR = 0b0001,
@@ -68,6 +74,6 @@ enum class ShiftType {
// https://fmt.dev/dev/api.html#std-ostream-support
std::ostream&
operator<<(std::ostream& os, const Condition cond);
operator<<(std::ostream& os, const ShiftType cond);
template<>
struct fmt::formatter<Condition> : ostream_formatter {};
struct fmt::formatter<ShiftType> : ostream_formatter {};