KEK/cpu.h
folkert van heusden e99d1bb6d0
RL02 tweaks
2024-04-17 17:15:13 +02:00

185 lines
6.1 KiB
C++

// (C) 2018-2024 by Folkert van Heusden
// Released under MIT license
#pragma once
#include <assert.h>
#include <condition_variable>
#include <map>
#include <mutex>
#include <optional>
#include <set>
#include <stdint.h>
#include <vector>
#include "breakpoint.h"
#include "bus.h"
constexpr const int max_stacktrace_depth = 16;
typedef struct {
int delta;
unsigned reg;
} mmr1_delta_t;
typedef struct {
word_mode_t word_mode;
rm_selection_t mode_selection;
d_i_space_t space;
int access_mode;
// for MMR1 register
std::optional<mmr1_delta_t> mmr1_update;
std::optional<uint16_t> addr;
std::optional<int> reg;
std::optional<uint16_t> value;
} gam_rc_t;
class cpu
{
private:
uint16_t regs0_5[2][6]; // R0...5, selected by bit 11 in PSW,
uint16_t sp[3 + 1]; // stackpointers, MF../MT.. select via 12/13 from PSW, others via 14/15
uint16_t pc { 0 };
uint16_t instruction_start { 0 };
uint16_t psw { 0 };
uint16_t fpsr { 0 };
uint16_t stackLimitRegister { 0377 };
int processing_trap_depth { 0 };
uint64_t instruction_count { 0 };
uint64_t running_since { 0 };
uint64_t wait_time { 0 };
bool it_is_a_trap { false };
bool debug_mode { false };
std::vector<std::pair<uint16_t, std::string> > stacktrace;
// level, vector
std::map<uint8_t, std::set<uint8_t> > queued_interrupts;
#if defined(BUILD_FOR_RP2040)
SemaphoreHandle_t qi_lock { xSemaphoreCreateBinary() };
QueueHandle_t qi_q { xQueueCreate(16, 1) };
#else
std::mutex qi_lock;
std::condition_variable qi_cv;
#endif
std::atomic_bool any_queued_interrupts { false };
std::map<int, breakpoint *> breakpoints;
int bp_nr { 0 };
bus *const b { nullptr };
std::atomic_uint32_t *const event { nullptr };
bool check_pending_interrupts() const; // needs the 'qi_lock'-lock
bool execute_any_pending_interrupt();
uint16_t addRegister(const int nr, const rm_selection_t mode_selection, const uint16_t value);
void addToMMR1(const gam_rc_t & g);
gam_rc_t getGAM(const uint8_t mode, const uint8_t reg, const word_mode_t word_mode, const rm_selection_t mode_selection, const bool read_value = true);
gam_rc_t getGAMAddress(const uint8_t mode, const int reg, const word_mode_t word_mode);
bool putGAM(const gam_rc_t & g, const uint16_t value); // returns false when flag registers should not be updated
bool double_operand_instructions(const uint16_t instr);
bool additional_double_operand_instructions(const uint16_t instr);
bool single_operand_instructions(const uint16_t instr);
bool conditional_branch_instructions(const uint16_t instr);
bool condition_code_operations(const uint16_t instr);
bool misc_operations(const uint16_t instr);
struct operand_parameters {
std::string operand;
int length;
int instruction_part;
uint16_t work_value;
};
operand_parameters addressing_to_string(const uint8_t mode_register, const uint16_t pc, const word_mode_t word_mode) const;
void add_to_stack_trace(const uint16_t p);
void pop_from_stack_trace();
public:
explicit cpu(bus *const b, std::atomic_uint32_t *const event);
~cpu();
std::optional<std::string> check_breakpoint();
int set_breakpoint(breakpoint *const bp);
bool remove_breakpoint(const int bp_id);
std::map<int, breakpoint *> list_breakpoints();
void disassemble(void) const;
std::map<std::string, std::vector<std::string> > disassemble(const uint16_t addr) const;
bus *getBus() { return b; }
void emulation_start();
uint64_t get_instructions_executed_count() const;
uint64_t get_wait_time() const { return wait_time; }
std::tuple<double, double, uint64_t, uint32_t, double> get_mips_rel_speed(const std::optional<uint64_t> & instruction_count, const std::optional<uint64_t> & t_diff_1s) const;
bool get_debug() const { return debug_mode; }
void set_debug(const bool d) { debug_mode = d; stacktrace.clear(); }
std::vector<std::pair<uint16_t, std::string> > get_stack_trace() const;
void reset();
void step();
void pushStack(const uint16_t v);
uint16_t popStack();
void init_interrupt_queue();
void queue_interrupt(const uint8_t level, const uint8_t vector);
void trap(uint16_t vector, const int new_ipl = -1, const bool is_interrupt = false);
bool is_it_a_trap() const { return it_is_a_trap; }
bool getPSW_c() const;
bool getPSW_v() const;
bool getPSW_z() const;
bool getPSW_n() const;
int getPSW_spl() const;
bool getBitPSW(const int bit) const;
int getPSW_runmode() const { return psw >> 14; };
int getPSW_prev_runmode() const { return (psw >> 12) & 3; };
void setPSW_c(const bool v);
void setPSW_v(const bool v);
void setPSW_z(const bool v);
void setPSW_n(const bool v);
void setPSW_spl(const int v);
void setBitPSW(const int bit, const bool v);
void setPSW_flags_nzv(const uint16_t value, const word_mode_t word_mode);
uint16_t getPSW() const { return psw; }
void setPSW(const uint16_t v, const bool limited);
uint16_t getStackLimitRegister() { return stackLimitRegister; }
void setStackLimitRegister(const uint16_t v) { stackLimitRegister = v; }
uint16_t getStackPointer(const int which) const { assert(which >= 0 && which < 4); return sp[which]; }
uint16_t getPC() const { return pc; }
void setRegister(const int nr, const uint16_t value, const rm_selection_t mode_selection = rm_cur);
void setRegisterLowByte(const int nr, const word_mode_t word_mode, const uint16_t value);
// used by 'main' for json-validation
void lowlevel_register_set(const uint8_t set, const uint8_t reg, const uint16_t value);
void lowlevel_register_sp_set(const uint8_t set, const uint16_t value);
uint16_t lowlevel_register_get(const uint8_t set, const uint8_t reg);
void lowlevel_psw_set(const uint16_t value) { psw = value; }
uint16_t lowlevel_register_sp_get(const uint8_t nr) const { return sp[nr]; }
void setStackPointer(const int which, const uint16_t value) { assert(which >= 0 && which < 4); sp[which] = value; }
void setPC(const uint16_t value) { pc = value; }
uint16_t getRegister(const int nr, const rm_selection_t mode_selection = rm_cur) const;
bool put_result(const gam_rc_t & g, const uint16_t value);
};