Last active
March 18, 2016 19:10
-
-
Save gazliddon/198fa11629cd6b72776e to your computer and use it in GitHub Desktop.
asd
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "isa.h" | |
#include "six8.h" | |
#include <map> | |
#include <unordered_map> | |
#include <iostream> | |
namespace six8 { | |
//////////////////////////////////////////////////////////////////////////////// | |
// ALU op code synthesis etc | |
static constexpr auto isNeg( uint8_t _v ) { | |
return ( _v & 0x80 ) == 0x80; | |
} | |
static constexpr auto isZero( uint8_t _v ) { | |
return ( _v & 0x80 ) == 0x80; | |
} | |
static constexpr auto hasCarried( uint8_t original, uint8_t now ) { | |
return now < original; | |
} | |
// Addressing modes | |
// | |
namespace detail { | |
template <typename I> | |
struct addr_immediate_t { | |
static constexpr uint8_t size() { | |
return sizeof( I ); | |
} | |
static I get( memory_t &m, regs_t &r ) { | |
auto ret = m.get<I>( r.pc ); | |
return ret; | |
} | |
}; | |
} /* detail */ | |
struct addr_direct_t { | |
static constexpr uint8_t size() { | |
return 1; | |
} | |
static uint8_t get( memory_t &m, regs_t &r ) { | |
auto addr = m.getByte( r.pc ); | |
auto ret = m.getByte( addr ); | |
return ret; | |
} | |
static void put( uint8_t _val, memory_t &m, regs_t &r ) { | |
auto addr = m.getByte( r.pc ); | |
m.setByte( _val, addr ); | |
} | |
}; | |
namespace detail { | |
template <typename I> | |
struct addr_extended_t { | |
static constexpr uint8_t size() { | |
return 2; | |
} | |
static I get( memory_t &m, regs_t &r ) { | |
auto addrlo = m.getByte( r.pc ); | |
auto addrhi = m.getByte( r.pc + 1 ); | |
auto ret = m.get<I>( addrlo + ( addrhi << 8 ) ); | |
return ret; | |
} | |
static void put( I _val, memory_t &m, regs_t &r ) { | |
auto addrlo = m.getByte( r.pc ); | |
auto addrhi = m.getByte( r.pc + 1 ); | |
m.set<I>( addrlo + ( addrhi << 8 ), _val ); | |
} | |
}; | |
} /* detail */ | |
struct addr_indexed_t { | |
static constexpr uint8_t size() { | |
return 1; | |
} | |
static uint8_t get( memory_t &m, regs_t &r ) { | |
uint16_t addr = m.getByte( r.pc ) + r.ix; | |
auto ret = m.get<uint8_t>( addr ); | |
return ret; | |
} | |
static void put( uint8_t _v, memory_t &m, regs_t &r ) { | |
uint16_t addr = m.getByte( r.pc ) + r.ix; | |
m.set( addr, _v ); | |
} | |
}; | |
struct addr_a_t { | |
static constexpr uint8_t size() { | |
return 0; | |
} | |
static uint8_t get( memory_t &m, regs_t &r ) { | |
return r.a; | |
} | |
static void put( uint8_t val, memory_t &m, regs_t &r ) { | |
r.a = val; | |
} | |
}; | |
struct addr_nothing_t { | |
static constexpr uint8_t size() { | |
return 0; | |
} | |
static constexpr auto get( memory_t &, regs_t & ) { | |
return 0; | |
} | |
}; | |
struct addr_b_t { | |
static constexpr uint8_t size() { | |
return 0; | |
} | |
static uint8_t get( memory_t &m, regs_t &r ) { | |
return r.b; | |
} | |
static uint8_t getHi( memory_t &m, regs_t &r ) { | |
return 0; | |
} | |
static void put( uint8_t val, memory_t &m, regs_t &r ) { | |
r.b = val; | |
} | |
}; | |
struct addr_sp_t { | |
static constexpr uint8_t size() { | |
return 0; | |
} | |
static uint16_t get( memory_t &m, regs_t &r ) { | |
return r.sp; | |
} | |
static void put( uint16_t val, memory_t &m, regs_t &r ) { | |
r.sp = val; | |
} | |
}; | |
struct addr_x_t { | |
static constexpr uint8_t size() { | |
return 0; | |
} | |
static uint16_t get( memory_t &m, regs_t &r ) { | |
return r.ix; | |
} | |
static void put( uint16_t val, memory_t &m, regs_t &r ) { | |
r.ix = val; | |
} | |
}; | |
//////////////////////////////////////////////////////////////////////////////// | |
namespace detail { | |
template <typename I> | |
struct alu_passthrough_a_t { | |
static constexpr I exec( I a, I, regs_t & ) { | |
return a; | |
} | |
}; | |
} /* detail */ | |
using alu_passthrough_word_t = detail::alu_passthrough_a_t<uint16_t>; | |
using alu_passthrough_byte_t = detail::alu_passthrough_a_t<uint8_t>; | |
struct alu_add_t { | |
static uint8_t exec( uint8_t _a, uint8_t _b, regs_t &r ) { | |
uint8_t res = _a + _b; | |
r.N = isNeg( res ); | |
r.Z = isZero( res ); | |
r.C = hasCarried( _a, res ); | |
return res; | |
} | |
}; | |
//////////////////////////////////////////////////////////////////////////////// | |
template <size_t OPCODE, | |
typename OP_INFO, | |
typename SRC_A, | |
typename SRC_B, | |
typename DST, | |
typename OP> | |
struct op_t { | |
static void exec( memory_t &m, regs_t &r ) { | |
auto sizeA = SRC_A::size(); | |
auto sizeB = SRC_B::size(); | |
r.pc++; | |
auto a = SRC_A::get( m, r ); | |
r.pc += sizeA; | |
auto b = SRC_B::get( m, r ); | |
r.pc += sizeB; | |
auto res = OP::exec( a, b, r ); | |
DST::put( res, m, r ); | |
} | |
static const uint8_t op = OPCODE; | |
static constexpr size_t size() { | |
return SRC_A::size() + SRC_B::size(); | |
} | |
static constexpr unsigned cycles() { | |
return 0; | |
} | |
static constexpr char const *getText() { | |
return OP_INFO::getText(); | |
} | |
}; | |
using addr_extended_word_t = detail::addr_extended_t<uint16_t>; | |
using addr_extended_byte_t = detail::addr_extended_t<uint8_t>; | |
using addr_immediate_word_t = detail::addr_immediate_t<uint16_t>; | |
using addr_immediate_byte_t = detail::addr_immediate_t<uint8_t>; | |
struct lds_t { | |
static constexpr char const *getText() { | |
return "lds"; | |
} | |
}; | |
struct clr_t { | |
static constexpr char const *getText() { | |
return "clr"; | |
} | |
using types = shitlib::mpl::list< // | |
op_t<127, | |
clr_t, | |
addr_nothing_t, | |
addr_nothing_t, | |
addr_extended_word_t, | |
alu_passthrough_word_t>, | |
op_t<111, | |
clr_t, | |
addr_nothing_t, | |
addr_nothing_t, | |
addr_indexed_t, | |
alu_passthrough_byte_t>>; | |
}; | |
struct ldx_t { | |
static constexpr char const *getText() { | |
return "clr"; | |
} | |
}; | |
using lds_immediate_op = op_t<142, | |
lds_t, | |
addr_immediate_word_t, | |
addr_nothing_t, | |
addr_sp_t, | |
alu_passthrough_word_t>; | |
using clr_extended_op = op_t<127, | |
clr_t, | |
addr_nothing_t, | |
addr_nothing_t, | |
addr_extended_word_t, | |
alu_passthrough_word_t>; | |
using clr_indexed_op = op_t<111, | |
clr_t, | |
addr_nothing_t, | |
addr_nothing_t, | |
addr_indexed_t, | |
alu_passthrough_byte_t>; | |
using ldx_extended_op = op_t<206, | |
ldx_t, | |
addr_extended_word_t, | |
addr_nothing_t, | |
addr_x_t, | |
alu_passthrough_word_t>; | |
//////////////////////////////////////////////////////////////////////////////// | |
// stack | |
template <size_t SIZE, unsigned CYCLES, typename BASE> | |
struct opcode_t { | |
static constexpr auto size() { | |
return SIZE; | |
} | |
static constexpr auto cycles() { | |
return CYCLES; | |
} | |
}; | |
struct psha_op : public opcode_t<1, 1, psh_op> { | |
static void exec( memory_t &m, regs_t &r ) { | |
m.setByte( r.sp, r.a ); | |
r.sp--; | |
r.pc++; | |
} | |
static constexpr char const *getText() { | |
return "psha"; | |
} | |
static const uint8_t op = 0x36; | |
}; | |
struct pshb_op : public opcode_t<1, 1, psh_op> { | |
static void exec( memory_t &m, regs_t &r ) { | |
m.setByte( r.sp, r.b ); | |
r.sp--; | |
r.pc++; | |
} | |
static constexpr char const *getText() { | |
return "psha"; | |
} | |
static const uint8_t op = 0x37; | |
}; | |
struct pula_op : public opcode_t<1, 1, pul_op> { | |
static void exec( memory_t &m, regs_t &r ) { | |
r.sp++; | |
r.a = m.getByte( r.sp ); | |
r.pc++; | |
} | |
static constexpr char const *getText() { | |
return "pula"; | |
} | |
static const uint8_t op = 0x32; | |
}; | |
struct pulb_op : public opcode_t<1, 1, pul_op> { | |
static void exec( memory_t &m, regs_t &r ) { | |
r.sp++; | |
r.b = m.getByte( r.sp ); | |
r.pc++; | |
} | |
static constexpr char const *getText() { | |
return "pulb"; | |
} | |
static const uint8_t op = 0x33; | |
}; | |
struct rts_op : public opcode_t<1, 1, rts_op> { | |
static void exec( memory_t &m, regs_t &r ) { | |
auto pchi = m.getByte( r.sp + 1 ); | |
auto pclo = m.getByte( r.sp + 2 ); | |
r.setPc( pclo, pchi ); | |
r.sp += 2; | |
} | |
static constexpr char const *getText() { | |
return "rts"; | |
} | |
static const uint8_t op = 0x39; | |
}; | |
//////////////////////////////////////////////////////////////////////////////// | |
// Interrupt comtrol | |
struct cli_op : public opcode_t<1, 1, cli_op> { | |
static void exec( memory_t &m, regs_t &r ) { | |
r.I = false; | |
r.pc++; | |
} | |
static constexpr char const *getText() { | |
return "cli"; | |
} | |
static const uint8_t op = 0x00; | |
}; | |
struct sei_op : public opcode_t<1, 1, sei_op> { | |
static void exec( memory_t &m, regs_t &r ) { | |
r.I = 1; | |
r.pc++; | |
} | |
static constexpr char const *getText() { | |
return "sei"; | |
} | |
static const uint8_t op = 0x0f; | |
}; | |
struct rti_op : public opcode_t<1, 1, rti_op> { | |
static void exec( memory_t &m, regs_t &r ) { | |
auto sp = r.sp; | |
r.setFlags( m.getByte( sp + 1 ) ); | |
r.b = m.getByte( sp + 2 ); | |
r.a = m.getByte( sp + 3 ); | |
r.ix = m.getWord( sp + 4 ); | |
r.pc = m.getWord( sp + 6 ); | |
r.sp += 7; | |
} | |
static constexpr char const *getText() { | |
return "swi"; | |
} | |
static const uint8_t op = 0x00; | |
}; | |
struct swi_op : public opcode_t<1, 1, swi_op> { | |
static void exec( memory_t &m, regs_t &r ) { | |
auto sp = r.sp; | |
auto flags = r.getFlags(); | |
m.setByte( sp + 0, r.pc & 0xff ); | |
m.setByte( sp + 1, r.pc >> 8 ); | |
m.setByte( sp + 2, r.ix >> 8 ); | |
m.setByte( sp + 3, r.ix & 0xff ); | |
m.setByte( sp + 4, r.a ); | |
m.setByte( sp + 5, r.b ); | |
m.setByte( sp + 6, flags ); | |
r.sp -= 7; | |
auto pchi = m.getByte( 0xfffa ); | |
auto pclo = m.getByte( 0xfffa ); | |
r.setPc( pclo, pchi ); | |
} | |
static constexpr char const *getText() { | |
return "swi"; | |
} | |
static const uint8_t op = 0x00; | |
}; | |
//////////////////////////////////////////////////////////////////////////////// | |
// Reg status | |
struct clc_op : public opcode_t<1, 1, clc_op> { | |
static void exec( memory_t &m, regs_t &r ) { | |
r.C = false; | |
r.pc++; | |
} | |
static constexpr char const *getText() { | |
return "cls"; | |
} | |
static const uint8_t op = 0x00; | |
}; | |
struct sec_op : public opcode_t<1, 1, sec_op> { | |
static void exec( memory_t &m, regs_t &r ) { | |
r.C = true; | |
r.pc++; | |
} | |
static constexpr char const *getText() { | |
return "sec"; | |
} | |
static const uint8_t op = 0x00; | |
}; | |
struct clv_op : public opcode_t<1, 1, clv_op> { | |
static void exec( memory_t &m, regs_t &r ) { | |
assert( false ); | |
} | |
static constexpr char const *getText() { | |
return "clv"; | |
} | |
static const uint8_t op = 0x00; | |
}; | |
struct sev_op : public opcode_t<1, 1, sev_op> { | |
static void exec( memory_t &m, regs_t &r ) { | |
assert( false ); | |
} | |
static constexpr char const *getText() { | |
return "sev"; | |
} | |
static constexpr char const optext[] = "sev"; | |
static const uint8_t op = 0x00; | |
}; | |
struct tap_op : public opcode_t<1, 1, tap_op> { | |
static void exec( memory_t &m, regs_t &r ) { | |
assert( false ); | |
} | |
static constexpr char const *getText() { | |
return "tpa"; | |
} | |
static const uint8_t op = 0x00; | |
}; | |
struct tpa_op : public opcode_t<1, 1, tpa_op> { | |
static void exec( memory_t &m, regs_t &r ) { | |
assert( false ); | |
} | |
static constexpr char const *getText() { | |
return "tpa"; | |
} | |
static const uint8_t op = 0x00; | |
}; | |
//////////////////////////////////////////////////////////////////////////////// | |
// Nop | |
struct nop_op : public opcode_t<1, 1, nop_op> { | |
static void exec( memory_t &m, regs_t &r ) { | |
} | |
static constexpr char const *getText() { | |
return "nop"; | |
} | |
static const uint8_t op = 0x00; | |
}; | |
struct instruction_t { | |
instruction_t() : mCycles( 0 ), mExec( nullptr ), mText( nullptr ) { | |
} | |
bool isValid() const { | |
return mExec != nullptr; | |
} | |
unsigned mCycles; | |
void ( *mExec )( memory_t &_m, regs_t &_r ); | |
char const *mText; | |
}; | |
template <typename T> | |
instruction_t mkInstruction() { | |
instruction_t ret; | |
ret.mCycles = T::cycles(); | |
ret.mExec = T::exec; | |
ret.mText = T::getText(); | |
return ret; | |
} | |
template <typename... Ts> | |
auto mkArray() { | |
std::array<instruction_t, 256> ret; | |
int dummy[] = {( ret[ Ts::op ] = mkInstruction<Ts>(), 0 )...}; | |
return ret; | |
} | |
static auto const sInstructions = mkArray<pula_op, | |
psha_op, | |
pshb_op, | |
rts_op, | |
cli_op, | |
sei_op, | |
rti_op, | |
swi_op, | |
clc_op, | |
sec_op, | |
clv_op, | |
sev_op, | |
tap_op, | |
tpa_op, | |
nop_op, | |
clr_indexed_op, | |
lds_immediate_op, | |
ldx_extended_op, | |
clr_extended_op>(); | |
//////////////////////////////////////////////////////////////////////////////// | |
size_t isa_t::execute( cpu_t &_cpu ) { | |
using namespace std; | |
auto &m = *_cpu.mpMem; | |
auto &r = _cpu.mRegisters; | |
int op = m.getByte( r.pc ); | |
auto &ins = sInstructions[ op ]; | |
if ( ins.isValid() ) { | |
cout << "PC: " << hex << r.pc << " " << ins.mText << endl; | |
ins.mExec( m, r ); | |
return ins.mCycles; | |
} else { | |
cout << "PC: " << hex << r.pc << " " | |
<< "FAILED 0x" << hex << op << " DEC " << dec << op << endl; | |
assert( false ); | |
} | |
return 0; | |
} | |
} /* six8 */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment