Skip to content

Instantly share code, notes, and snippets.

@gazliddon
Last active March 18, 2016 19:10
Show Gist options
  • Save gazliddon/198fa11629cd6b72776e to your computer and use it in GitHub Desktop.
Save gazliddon/198fa11629cd6b72776e to your computer and use it in GitHub Desktop.
asd
#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