From 8054ac43ac7fb8ef09934025f696d68932a6d38e Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Sun, 20 Mar 2022 15:50:14 -0700 Subject: [PATCH] initial --- .gitignore | 3 + Makefile | 23 ++ addressing_mode.cc | 35 +++ addressing_mode.hh | 13 ++ assembler.hh | 30 +++ codec.cc | 563 +++++++++++++++++++++++++++++++++++++++++++++ codec.hh | 12 + field.hh | 0 fromstring.cc | 133 +++++++++++ fromstring.hh | 14 ++ isa.hh | 125 ++++++++++ main.cc | 137 +++++++++++ mneumonic.hh | 127 ++++++++++ parser.cc | 261 +++++++++++++++++++++ parser.hh | 9 + tostring.cc | 127 ++++++++++ tostring.hh | 11 + 17 files changed, 1623 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 addressing_mode.cc create mode 100644 addressing_mode.hh create mode 100644 assembler.hh create mode 100644 codec.cc create mode 100644 codec.hh create mode 100644 field.hh create mode 100644 fromstring.cc create mode 100644 fromstring.hh create mode 100644 isa.hh create mode 100644 main.cc create mode 100644 mneumonic.hh create mode 100644 parser.cc create mode 100644 parser.hh create mode 100644 tostring.cc create mode 100644 tostring.hh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2567f0c --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.o +*.asm +main diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..39fae9b --- /dev/null +++ b/Makefile @@ -0,0 +1,23 @@ +CXXFLAGS = -O0 -g -Wall -Wextra -Werror -Wpedantic -std=c++20 -Wno-error=unused-parameter -Wno-error=unused-but-set-variable -fPIE +LDFLAGS = + +TARGET = +CXX = $(TARGET)g++ + +OBJS = main.o fromstring.o addressing_mode.o codec.o parser.o +HEADERS = $(wildcard *.h) + +all: main + +%.o: %.cc $(HEADERS) Makefile + $(CXX) $(CXXFLAGS) -c $< -o $@ + +main: $(OBJS) + $(CXX) $(LDFLAGS) $^ -o $@ + +clean: + rm -f *.o *.elf *.bin *.out *.imem *.hex + +.SUFFIXES: +.INTERMEDIATE: +.PHONY: all clean %.dump diff --git a/addressing_mode.cc b/addressing_mode.cc new file mode 100644 index 0000000..ac53d8d --- /dev/null +++ b/addressing_mode.cc @@ -0,0 +1,35 @@ +#include +#include + +#include "addressing_mode.hh" +#include "isa.hh" + +static bool is_uint16(ssize_t n) { return n >= 0 && n <= 65535; } + +static bool is_uint8(ssize_t n) { return n >= 0 && n <= 255; } + +static bool is_int8(ssize_t n) { return n >= -128 && n <= 127; } + +static bool always_valid(ssize_t _) { return true; } + +std::unordered_map& addressing_mode() { + static std::unordered_map _ = { + {isa::mode::A, { .len = 2, .valid = is_uint16 }}, + {isa::mode::AII, { .len = 2, .valid = is_uint16 }}, + {isa::mode::AIX, { .len = 2, .valid = is_uint16 }}, + {isa::mode::AIY, { .len = 2, .valid = is_uint16 }}, + {isa::mode::AI, { .len = 2, .valid = is_uint16 }}, + {isa::mode::ACC, { .len = 0, .valid = always_valid }}, + {isa::mode::IMM, { .len = 1, .valid = is_uint8 }}, + {isa::mode::I, { .len = 0, .valid = always_valid }}, + {isa::mode::R, { .len = 1, .valid = is_int8 }}, + {isa::mode::S, { .len = 0, .valid = always_valid }}, + {isa::mode::ZP, { .len = 1, .valid = is_uint8 }}, + {isa::mode::ZPII, { .len = 1, .valid = is_uint8 }}, + {isa::mode::ZPX, { .len = 1, .valid = is_uint8 }}, + {isa::mode::ZPY, { .len = 1, .valid = is_uint8 }}, + {isa::mode::ZPI, { .len = 1, .valid = is_uint8 }}, + {isa::mode::ZPIY, { .len = 1, .valid = is_uint8 }}, + }; + return _; +} diff --git a/addressing_mode.hh b/addressing_mode.hh new file mode 100644 index 0000000..6d6f2fd --- /dev/null +++ b/addressing_mode.hh @@ -0,0 +1,13 @@ +#pragma once + +#include +#include + +#include "isa.hh" + +struct addressing_mode_t { + size_t len; + std::function valid; +}; + +std::unordered_map& addressing_mode(); diff --git a/assembler.hh b/assembler.hh new file mode 100644 index 0000000..5d26e38 --- /dev/null +++ b/assembler.hh @@ -0,0 +1,30 @@ +#pragma once + +#include +#include +#include + +#include "isa.hh" + +namespace assembler { + struct literal_t { + ssize_t num; + }; + + struct reference_t { + size_t symbol; + }; + + struct implied_t { + }; + + struct instruction_t { + std::optional symbol; + isa::op op; + isa::mode mode; + std::variant value; + size_t location; + }; + + using program_t = std::vector; +} diff --git a/codec.cc b/codec.cc new file mode 100644 index 0000000..083d6c4 --- /dev/null +++ b/codec.cc @@ -0,0 +1,563 @@ +#include +#include +#include +#include + +#include "codec.hh" +#include "isa.hh" + +namespace codec { + const std::map, uint8_t>& encode() { + static const std::map, uint8_t> _ = { + {{isa::op::BRK, isa::mode::S}, 0}, + {{isa::op::ORA, isa::mode::ZPX}, 1}, + //{{isa::op::O_INVALID, isa::mode::M_INVALID}, 2}, + //{{isa::op::O_INVALID, isa::mode::M_INVALID}, 3}, + {{isa::op::TSB, isa::mode::ZP}, 4}, + {{isa::op::ORA, isa::mode::ZP}, 5}, + {{isa::op::ASL, isa::mode::ZP}, 6}, + {{isa::op::RMB0, isa::mode::ZP}, 7}, + {{isa::op::PHP, isa::mode::S}, 8}, + {{isa::op::ORA, isa::mode::IMM}, 9}, + {{isa::op::ASL, isa::mode::A}, 10}, + //{{isa::op::O_INVALID, isa::mode::M_INVALID}, 11}, + {{isa::op::TSB, isa::mode::A}, 12}, + {{isa::op::ORA, isa::mode::A}, 13}, + {{isa::op::ASL, isa::mode::A}, 14}, + {{isa::op::BBR0, isa::mode::R}, 15}, + + {{isa::op::BPL, isa::mode::R}, 16}, + {{isa::op::ORA, isa::mode::ZPIY}, 17}, + {{isa::op::ORA, isa::mode::ZPI}, 18}, + //{{isa::op::O_INVALID, isa::mode::M_INVALID}, 19}, + {{isa::op::TRB, isa::mode::ZP}, 20}, + {{isa::op::ORA, isa::mode::ZPX}, 21}, + {{isa::op::ASL, isa::mode::ZPX}, 22}, + {{isa::op::RMB1, isa::mode::ZP}, 23}, + {{isa::op::CLC, isa::mode::I}, 24}, + {{isa::op::ORA, isa::mode::AIY}, 25}, + {{isa::op::INC, isa::mode::A}, 26}, + //{{isa::op::O_INVALID, isa::mode::M_INVALID}, 27}, + {{isa::op::TRB, isa::mode::A}, 28}, + {{isa::op::ORA, isa::mode::AIX}, 29}, + {{isa::op::ASL, isa::mode::AIX}, 30}, + {{isa::op::BBR1, isa::mode::R}, 31}, + + {{isa::op::JSR, isa::mode::A}, 32}, + {{isa::op::AND, isa::mode::ZPII}, 33}, + //{{isa::op::O_INVALID, isa::mode::M_INVALID}, 34}, + //{{isa::op::O_INVALID, isa::mode::M_INVALID}, 35}, + {{isa::op::BIT, isa::mode::ZP}, 36}, + {{isa::op::AND, isa::mode::ZP}, 37}, + {{isa::op::ROL, isa::mode::ZP}, 38}, + {{isa::op::RMB2, isa::mode::ZP}, 39}, + {{isa::op::PLP, isa::mode::S}, 40}, + {{isa::op::AND, isa::mode::IMM}, 41}, + {{isa::op::ROL, isa::mode::A}, 42}, + //{{isa::op::O_INVALID, isa::mode::M_INVALID}, 43}, + {{isa::op::BIT, isa::mode::A}, 44}, + {{isa::op::AND, isa::mode::A}, 45}, + {{isa::op::ROL, isa::mode::A}, 46}, + {{isa::op::BBR2, isa::mode::R}, 47}, + + {{isa::op::BMI, isa::mode::R}, 48}, + {{isa::op::AND, isa::mode::ZPIY}, 49}, + {{isa::op::AND, isa::mode::ZPI}, 50}, + //{{isa::op::O_INVALID, isa::mode::M_INVALID}, 51}, + {{isa::op::BIT, isa::mode::ZPX}, 52}, + {{isa::op::AND, isa::mode::ZPX}, 53}, + {{isa::op::ROL, isa::mode::ZPX}, 54}, + {{isa::op::RMB3, isa::mode::ZP}, 55}, + {{isa::op::SEC, isa::mode::I}, 56}, + {{isa::op::AND, isa::mode::AIY}, 57}, + {{isa::op::DEC, isa::mode::A}, 58}, + //{{isa::op::O_INVALID, isa::mode::M_INVALID}, 59}, + {{isa::op::BIT, isa::mode::AIX}, 60}, + {{isa::op::AND, isa::mode::AIX}, 61}, + {{isa::op::ROL, isa::mode::AIX}, 62}, + {{isa::op::BBR3, isa::mode::R}, 63}, + + {{isa::op::RTI, isa::mode::S}, 64}, + {{isa::op::EOR, isa::mode::ZPII}, 65}, + //{{isa::op::O_INVALID, isa::mode::M_INVALID}, 66}, + //{{isa::op::O_INVALID, isa::mode::M_INVALID}, 67}, + //{{isa::op::O_INVALID, isa::mode::M_INVALID}, 68}, + {{isa::op::EOR, isa::mode::ZP}, 69}, + {{isa::op::LSR, isa::mode::ZP}, 70}, + {{isa::op::RMB4, isa::mode::ZP}, 71}, + {{isa::op::PHA, isa::mode::S}, 72}, + {{isa::op::EOR, isa::mode::IMM}, 73}, + {{isa::op::LSR, isa::mode::A}, 74}, + //{{isa::op::O_INVALID, isa::mode::M_INVALID}, 75}, + {{isa::op::JMP, isa::mode::A}, 76}, + {{isa::op::EOR, isa::mode::A}, 77}, + {{isa::op::LSR, isa::mode::A}, 78}, + {{isa::op::BBR4, isa::mode::R}, 79}, + + {{isa::op::BVC, isa::mode::R}, 80}, + {{isa::op::EOR, isa::mode::ZPIY}, 81}, + {{isa::op::EOR, isa::mode::ZPI}, 82}, + {{isa::op::EOR, isa::mode::ZPX}, 83}, + //{{isa::op::O_INVALID, isa::mode::M_INVALID}, 84}, + //{{isa::op::O_INVALID, isa::mode::M_INVALID}, 85}, + {{isa::op::LSR, isa::mode::ZPX}, 86}, + {{isa::op::RMB5, isa::mode::ZP}, 87}, + {{isa::op::CLI, isa::mode::I}, 88}, + {{isa::op::EOR, isa::mode::AIY}, 89}, + {{isa::op::PHY, isa::mode::S}, 90}, + //{{isa::op::O_INVALID, isa::mode::M_INVALID}, 91}, + //{{isa::op::O_INVALID, isa::mode::M_INVALID}, 92}, + {{isa::op::EOR, isa::mode::AIX}, 93}, + {{isa::op::LSR, isa::mode::AIX}, 94}, + {{isa::op::BBR5, isa::mode::R}, 95}, + + {{isa::op::RTS, isa::mode::S}, 96}, + {{isa::op::ADC, isa::mode::ZPII}, 97}, + //{{isa::op::O_INVALID, isa::mode::M_INVALID}, 98}, + //{{isa::op::O_INVALID, isa::mode::M_INVALID}, 99}, + {{isa::op::STZ, isa::mode::ZP}, 100}, + {{isa::op::ADC, isa::mode::ZP}, 101}, + {{isa::op::ROR, isa::mode::ZP}, 102}, + {{isa::op::RMB6, isa::mode::ZP}, 103}, + {{isa::op::PLA, isa::mode::S}, 104}, + {{isa::op::ADC, isa::mode::IMM}, 105}, + {{isa::op::ROR, isa::mode::A}, 106}, + //{{isa::op::O_INVALID, isa::mode::M_INVALID}, 107}, + {{isa::op::JMP, isa::mode::AI}, 108}, + {{isa::op::ADC, isa::mode::A}, 109}, + {{isa::op::ROR, isa::mode::A}, 110}, + {{isa::op::BBR6, isa::mode::R}, 111}, + + {{isa::op::BVS, isa::mode::R}, 112}, + {{isa::op::ADC, isa::mode::ZPIY}, 113}, + {{isa::op::ADC, isa::mode::ZPI}, 114}, + //{{isa::op::O_INVALID, isa::mode::M_INVALID}, 115}, + {{isa::op::STZ, isa::mode::ZPX}, 116}, + {{isa::op::ADC, isa::mode::ZPX}, 117}, + {{isa::op::ROR, isa::mode::ZPX}, 118}, + {{isa::op::RMB7, isa::mode::ZP}, 119}, + {{isa::op::SEI, isa::mode::I}, 120}, + {{isa::op::ADC, isa::mode::AIY}, 121}, + {{isa::op::PLY, isa::mode::S}, 122}, + //{{isa::op::O_INVALID, isa::mode::M_INVALID}, 123}, + {{isa::op::JMP, isa::mode::AII}, 124}, + {{isa::op::ADC, isa::mode::AIX}, 125}, + {{isa::op::ROR, isa::mode::AIX}, 126}, + {{isa::op::BBR7, isa::mode::R}, 127}, + + {{isa::op::BRA, isa::mode::R}, 128}, + {{isa::op::STA, isa::mode::ZPII}, 129}, + //{{isa::op::O_INVALID, isa::mode::M_INVALID}, 130}, + //{{isa::op::O_INVALID, isa::mode::M_INVALID}, 131}, + {{isa::op::STY, isa::mode::ZP}, 132}, + {{isa::op::STA, isa::mode::ZP}, 133}, + {{isa::op::STX, isa::mode::ZP}, 134}, + {{isa::op::SMB0, isa::mode::ZP}, 135}, + {{isa::op::DEY, isa::mode::I}, 136}, + {{isa::op::BIT, isa::mode::IMM}, 137}, + {{isa::op::TXA, isa::mode::I}, 138}, + //{{isa::op::O_INVALID, isa::mode::M_INVALID}, 139}, + {{isa::op::STY, isa::mode::A}, 140}, + {{isa::op::STA, isa::mode::A}, 141}, + {{isa::op::STX, isa::mode::A}, 142}, + {{isa::op::BBS0, isa::mode::R}, 143}, + + {{isa::op::BCC, isa::mode::R}, 144}, + {{isa::op::STA, isa::mode::ZPIY}, 145}, + {{isa::op::STA, isa::mode::ZPI}, 146}, + //{{isa::op::O_INVALID, isa::mode::M_INVALID}, 147}, + {{isa::op::STY, isa::mode::ZPX}, 148}, + {{isa::op::STA, isa::mode::ZPX}, 149}, + {{isa::op::STX, isa::mode::ZPY}, 150}, + {{isa::op::SMB1, isa::mode::ZP}, 151}, + {{isa::op::TYA, isa::mode::I}, 152}, + {{isa::op::STA, isa::mode::AIY}, 153}, + {{isa::op::TXS, isa::mode::I}, 154}, + //{{isa::op::O_INVALID, isa::mode::M_INVALID}, 155}, + {{isa::op::STZ, isa::mode::A}, 156}, + {{isa::op::STA, isa::mode::AIX}, 157}, + {{isa::op::STZ, isa::mode::AIX}, 158}, + {{isa::op::BBS1, isa::mode::R}, 159}, + + {{isa::op::LDY, isa::mode::IMM}, 160}, + {{isa::op::LDA, isa::mode::ZPII}, 161}, + {{isa::op::LDX, isa::mode::IMM}, 162}, + //{{isa::op::O_INVALID, isa::mode::M_INVALID}, 163}, + {{isa::op::LDY, isa::mode::ZP}, 164}, + {{isa::op::LDA, isa::mode::ZP}, 165}, + {{isa::op::LDX, isa::mode::ZP}, 166}, + {{isa::op::SMB2, isa::mode::ZP}, 167}, + {{isa::op::TAY, isa::mode::I}, 168}, + {{isa::op::LDA, isa::mode::IMM}, 169}, + {{isa::op::TAX, isa::mode::I}, 170}, + //{{isa::op::O_INVALID, isa::mode::M_INVALID}, 171}, + {{isa::op::LDY, isa::mode::A}, 172}, + {{isa::op::LDA, isa::mode::A}, 173}, + {{isa::op::LDX, isa::mode::A}, 174}, + {{isa::op::BBS2, isa::mode::R}, 175}, + + {{isa::op::BCS, isa::mode::R}, 176}, + {{isa::op::LDA, isa::mode::ZPIY}, 177}, + {{isa::op::LDA, isa::mode::ZPI}, 178}, + //{{isa::op::O_INVALID, isa::mode::M_INVALID}, 179}, + {{isa::op::LDY, isa::mode::ZPX}, 180}, + {{isa::op::LDA, isa::mode::ZPX}, 181}, + {{isa::op::LDX, isa::mode::ZPY}, 182}, + {{isa::op::SMB3, isa::mode::ZP}, 183}, + {{isa::op::CLV, isa::mode::I}, 184}, + {{isa::op::LDA, isa::mode::AIY}, 185}, + {{isa::op::TSX, isa::mode::I}, 186}, + //{{isa::op::O_INVALID, isa::mode::M_INVALID}, 187}, + {{isa::op::LDY, isa::mode::AIX}, 188}, + {{isa::op::LDA, isa::mode::AIX}, 189}, + {{isa::op::LDX, isa::mode::AIY}, 190}, + {{isa::op::BBS3, isa::mode::R}, 191}, + + {{isa::op::CPY, isa::mode::IMM}, 192}, + {{isa::op::CMP, isa::mode::ZPII}, 193}, + //{{isa::op::O_INVALID, isa::mode::M_INVALID}, 194}, + //{{isa::op::O_INVALID, isa::mode::M_INVALID}, 195}, + {{isa::op::CPY, isa::mode::ZP}, 196}, + {{isa::op::CMP, isa::mode::ZP}, 197}, + {{isa::op::DEC, isa::mode::ZP}, 198}, + {{isa::op::SMB4, isa::mode::ZP}, 199}, + {{isa::op::INY, isa::mode::I}, 200}, + {{isa::op::CMP, isa::mode::IMM}, 201}, + {{isa::op::DEX, isa::mode::I}, 202}, + {{isa::op::WAI, isa::mode::I}, 203}, + {{isa::op::CPY, isa::mode::A}, 204}, + {{isa::op::CMP, isa::mode::A}, 205}, + {{isa::op::DEC, isa::mode::A}, 206}, + {{isa::op::BBS4, isa::mode::R}, 207}, + + {{isa::op::BNE, isa::mode::R}, 208}, + {{isa::op::CMP, isa::mode::ZPIY}, 209}, + {{isa::op::CMP, isa::mode::ZPI}, 210}, + //{{isa::op::O_INVALID, isa::mode::M_INVALID}, 211}, + //{{isa::op::O_INVALID, isa::mode::M_INVALID}, 212}, + {{isa::op::CMP, isa::mode::ZPX}, 213}, + {{isa::op::DEC, isa::mode::ZPX}, 214}, + {{isa::op::SMB5, isa::mode::ZP}, 215}, + {{isa::op::CLD, isa::mode::I}, 216}, + {{isa::op::CMP, isa::mode::AIY}, 217}, + {{isa::op::PHX, isa::mode::S}, 218}, + {{isa::op::STP, isa::mode::I}, 219}, + //{{isa::op::O_INVALID, isa::mode::M_INVALID}, 220}, + {{isa::op::CMP, isa::mode::AIX}, 221}, + {{isa::op::DEC, isa::mode::AIX}, 222}, + {{isa::op::BBS5, isa::mode::R}, 223}, + + {{isa::op::CPX, isa::mode::IMM}, 224}, + {{isa::op::SBC, isa::mode::ZPII}, 225}, + //{{isa::op::O_INVALID, isa::mode::M_INVALID}, 226}, + //{{isa::op::O_INVALID, isa::mode::M_INVALID}, 227}, + {{isa::op::CPX, isa::mode::ZP}, 228}, + {{isa::op::SBC, isa::mode::ZP}, 229}, + {{isa::op::INC, isa::mode::ZP}, 230}, + {{isa::op::SMB6, isa::mode::ZP}, 231}, + {{isa::op::INX, isa::mode::I}, 232}, + {{isa::op::SBC, isa::mode::IMM}, 233}, + {{isa::op::NOP, isa::mode::I}, 234}, + //{{isa::op::O_INVALID, isa::mode::M_INVALID}, 235}, + {{isa::op::CPX, isa::mode::A}, 236}, + {{isa::op::SBC, isa::mode::A}, 237}, + {{isa::op::INC, isa::mode::A}, 238}, + {{isa::op::BBS6, isa::mode::R}, 239}, + + {{isa::op::BEQ, isa::mode::R}, 240}, + {{isa::op::SBC, isa::mode::ZPIY}, 241}, + {{isa::op::SBC, isa::mode::ZPI}, 242}, + //{{isa::op::O_INVALID, isa::mode::M_INVALID}, 243}, + //{{isa::op::O_INVALID, isa::mode::M_INVALID}, 244}, + {{isa::op::SBC, isa::mode::ZPX}, 245}, + {{isa::op::INC, isa::mode::ZPX}, 246}, + {{isa::op::SMB7, isa::mode::ZP}, 247}, + {{isa::op::SED, isa::mode::I}, 248}, + {{isa::op::SBC, isa::mode::AIY}, 249}, + {{isa::op::PLX, isa::mode::S}, 250}, + //{{isa::op::O_INVALID, isa::mode::M_INVALID}, 251}, + //{{isa::op::O_INVALID, isa::mode::M_INVALID}, 252}, + {{isa::op::SBC, isa::mode::AIX}, 253}, + {{isa::op::INC, isa::mode::AIX}, 254}, + {{isa::op::BBS7, isa::mode::R}, 255}, + }; + return _; + } + + const std::map>& decode() { + static const std::map> _ = { + {0, {isa::op::BRK, isa::mode::S}}, + {1, {isa::op::ORA, isa::mode::ZPX}}, + //{2, {isa::op::O_INVALID, isa::mode::M_INVALID}}, + //{3, {isa::op::O_INVALID, isa::mode::M_INVALID}}, + {4, {isa::op::TSB, isa::mode::ZP}}, + {5, {isa::op::ORA, isa::mode::ZP}}, + {6, {isa::op::ASL, isa::mode::ZP}}, + {7, {isa::op::RMB0, isa::mode::ZP}}, + {8, {isa::op::PHP, isa::mode::S}}, + {9, {isa::op::ORA, isa::mode::IMM}}, + {10, {isa::op::ASL, isa::mode::A}}, + //{11, {isa::op::O_INVALID, isa::mode::M_INVALID}}, + {12, {isa::op::TSB, isa::mode::A}}, + {13, {isa::op::ORA, isa::mode::A}}, + {14, {isa::op::ASL, isa::mode::A}}, + {15, {isa::op::BBR0, isa::mode::R}}, + + {16, {isa::op::BPL, isa::mode::R}}, + {17, {isa::op::ORA, isa::mode::ZPIY}}, + {18, {isa::op::ORA, isa::mode::ZPI}}, + //{19, {isa::op::O_INVALID, isa::mode::M_INVALID}}, + {20, {isa::op::TRB, isa::mode::ZP}}, + {21, {isa::op::ORA, isa::mode::ZPX}}, + {22, {isa::op::ASL, isa::mode::ZPX}}, + {23, {isa::op::RMB1, isa::mode::ZP}}, + {24, {isa::op::CLC, isa::mode::I}}, + {25, {isa::op::ORA, isa::mode::AIY}}, + {26, {isa::op::INC, isa::mode::A}}, + //{27, {isa::op::O_INVALID, isa::mode::M_INVALID}}, + {28, {isa::op::TRB, isa::mode::A}}, + {29, {isa::op::ORA, isa::mode::AIX}}, + {30, {isa::op::ASL, isa::mode::AIX}}, + {31, {isa::op::BBR1, isa::mode::R}}, + + {32, {isa::op::JSR, isa::mode::A}}, + {33, {isa::op::AND, isa::mode::ZPII}}, + //{34, {isa::op::O_INVALID, isa::mode::M_INVALID}}, + //{35, {isa::op::O_INVALID, isa::mode::M_INVALID}}, + {36, {isa::op::BIT, isa::mode::ZP}}, + {37, {isa::op::AND, isa::mode::ZP}}, + {38, {isa::op::ROL, isa::mode::ZP}}, + {39, {isa::op::RMB2, isa::mode::ZP}}, + {40, {isa::op::PLP, isa::mode::S}}, + {41, {isa::op::AND, isa::mode::IMM}}, + {42, {isa::op::ROL, isa::mode::A}}, + //{43, {isa::op::O_INVALID, isa::mode::M_INVALID}}, + {44, {isa::op::BIT, isa::mode::A}}, + {45, {isa::op::AND, isa::mode::A}}, + {46, {isa::op::ROL, isa::mode::A}}, + {47, {isa::op::BBR2, isa::mode::R}}, + + {48, {isa::op::BMI, isa::mode::R}}, + {49, {isa::op::AND, isa::mode::ZPIY}}, + {50, {isa::op::AND, isa::mode::ZPI}}, + //{51, {isa::op::O_INVALID, isa::mode::M_INVALID}}, + {52, {isa::op::BIT, isa::mode::ZPX}}, + {53, {isa::op::AND, isa::mode::ZPX}}, + {54, {isa::op::ROL, isa::mode::ZPX}}, + {55, {isa::op::RMB3, isa::mode::ZP}}, + {56, {isa::op::SEC, isa::mode::I}}, + {57, {isa::op::AND, isa::mode::AIY}}, + {58, {isa::op::DEC, isa::mode::A}}, + //{59, {isa::op::O_INVALID, isa::mode::M_INVALID}}, + {60, {isa::op::BIT, isa::mode::AIX}}, + {61, {isa::op::AND, isa::mode::AIX}}, + {62, {isa::op::ROL, isa::mode::AIX}}, + {63, {isa::op::BBR3, isa::mode::R}}, + + {64, {isa::op::RTI, isa::mode::S}}, + {65, {isa::op::EOR, isa::mode::ZPII}}, + //{66, {isa::op::O_INVALID, isa::mode::M_INVALID}}, + //{67, {isa::op::O_INVALID, isa::mode::M_INVALID}}, + //{68, {isa::op::O_INVALID, isa::mode::M_INVALID}}, + {69, {isa::op::EOR, isa::mode::ZP}}, + {70, {isa::op::LSR, isa::mode::ZP}}, + {71, {isa::op::RMB4, isa::mode::ZP}}, + {72, {isa::op::PHA, isa::mode::S}}, + {73, {isa::op::EOR, isa::mode::IMM}}, + {74, {isa::op::LSR, isa::mode::A}}, + //{75, {isa::op::O_INVALID, isa::mode::M_INVALID}}, + {76, {isa::op::JMP, isa::mode::A}}, + {77, {isa::op::EOR, isa::mode::A}}, + {78, {isa::op::LSR, isa::mode::A}}, + {79, {isa::op::BBR4, isa::mode::R}}, + + {80, {isa::op::BVC, isa::mode::R}}, + {81, {isa::op::EOR, isa::mode::ZPIY}}, + {82, {isa::op::EOR, isa::mode::ZPI}}, + {83, {isa::op::EOR, isa::mode::ZPX}}, + //{84, {isa::op::O_INVALID, isa::mode::M_INVALID}}, + //{85, {isa::op::O_INVALID, isa::mode::M_INVALID}}, + {86, {isa::op::LSR, isa::mode::ZPX}}, + {87, {isa::op::RMB5, isa::mode::ZP}}, + {88, {isa::op::CLI, isa::mode::I}}, + {89, {isa::op::EOR, isa::mode::AIY}}, + {90, {isa::op::PHY, isa::mode::S}}, + //{91, {isa::op::O_INVALID, isa::mode::M_INVALID}}, + //{92, {isa::op::O_INVALID, isa::mode::M_INVALID}}, + {93, {isa::op::EOR, isa::mode::AIX}}, + {94, {isa::op::LSR, isa::mode::AIX}}, + {95, {isa::op::BBR5, isa::mode::R}}, + + {96, {isa::op::RTS, isa::mode::S}}, + {97, {isa::op::ADC, isa::mode::ZPII}}, + //{98, {isa::op::O_INVALID, isa::mode::M_INVALID}}, + //{99, {isa::op::O_INVALID, isa::mode::M_INVALID}}, + {100, {isa::op::STZ, isa::mode::ZP}}, + {101, {isa::op::ADC, isa::mode::ZP}}, + {102, {isa::op::ROR, isa::mode::ZP}}, + {103, {isa::op::RMB6, isa::mode::ZP}}, + {104, {isa::op::PLA, isa::mode::S}}, + {105, {isa::op::ADC, isa::mode::IMM}}, + {106, {isa::op::ROR, isa::mode::A}}, + //{107, {isa::op::O_INVALID, isa::mode::M_INVALID}}, + {108, {isa::op::JMP, isa::mode::AI}}, + {109, {isa::op::ADC, isa::mode::A}}, + {110, {isa::op::ROR, isa::mode::A}}, + {111, {isa::op::BBR6, isa::mode::R}}, + + {112, {isa::op::BVS, isa::mode::R}}, + {113, {isa::op::ADC, isa::mode::ZPIY}}, + {114, {isa::op::ADC, isa::mode::ZPI}}, + //{115, {isa::op::O_INVALID, isa::mode::M_INVALID}}, + {116, {isa::op::STZ, isa::mode::ZPX}}, + {117, {isa::op::ADC, isa::mode::ZPX}}, + {118, {isa::op::ROR, isa::mode::ZPX}}, + {119, {isa::op::RMB7, isa::mode::ZP}}, + {120, {isa::op::SEI, isa::mode::I}}, + {121, {isa::op::ADC, isa::mode::AIY}}, + {122, {isa::op::PLY, isa::mode::S}}, + //{123, {isa::op::O_INVALID, isa::mode::M_INVALID}}, + {124, {isa::op::JMP, isa::mode::AII}}, + {125, {isa::op::ADC, isa::mode::AIX}}, + {126, {isa::op::ROR, isa::mode::AIX}}, + {127, {isa::op::BBR7, isa::mode::R}}, + + {128, {isa::op::BRA, isa::mode::R}}, + {129, {isa::op::STA, isa::mode::ZPII}}, + //{130, {isa::op::O_INVALID, isa::mode::M_INVALID}}, + //{131, {isa::op::O_INVALID, isa::mode::M_INVALID}}, + {132, {isa::op::STY, isa::mode::ZP}}, + {133, {isa::op::STA, isa::mode::ZP}}, + {134, {isa::op::STX, isa::mode::ZP}}, + {135, {isa::op::SMB0, isa::mode::ZP}}, + {136, {isa::op::DEY, isa::mode::I}}, + {137, {isa::op::BIT, isa::mode::IMM}}, + {138, {isa::op::TXA, isa::mode::I}}, + //{139, {isa::op::O_INVALID, isa::mode::M_INVALID}}, + {140, {isa::op::STY, isa::mode::A}}, + {141, {isa::op::STA, isa::mode::A}}, + {142, {isa::op::STX, isa::mode::A}}, + {143, {isa::op::BBS0, isa::mode::R}}, + + {144, {isa::op::BCC, isa::mode::R}}, + {145, {isa::op::STA, isa::mode::ZPIY}}, + {146, {isa::op::STA, isa::mode::ZPI}}, + //{147, {isa::op::O_INVALID, isa::mode::M_INVALID}}, + {148, {isa::op::STY, isa::mode::ZPX}}, + {149, {isa::op::STA, isa::mode::ZPX}}, + {150, {isa::op::STX, isa::mode::ZPY}}, + {151, {isa::op::SMB1, isa::mode::ZP}}, + {152, {isa::op::TYA, isa::mode::I}}, + {153, {isa::op::STA, isa::mode::AIY}}, + {154, {isa::op::TXS, isa::mode::I}}, + //{155, {isa::op::O_INVALID, isa::mode::M_INVALID}}, + {156, {isa::op::STZ, isa::mode::A}}, + {157, {isa::op::STA, isa::mode::AIX}}, + {158, {isa::op::STZ, isa::mode::AIX}}, + {159, {isa::op::BBS1, isa::mode::R}}, + + {160, {isa::op::LDY, isa::mode::IMM}}, + {161, {isa::op::LDA, isa::mode::ZPII}}, + {162, {isa::op::LDX, isa::mode::IMM}}, + //{163, {isa::op::O_INVALID, isa::mode::M_INVALID}}, + {164, {isa::op::LDY, isa::mode::ZP}}, + {165, {isa::op::LDA, isa::mode::ZP}}, + {166, {isa::op::LDX, isa::mode::ZP}}, + {167, {isa::op::SMB2, isa::mode::ZP}}, + {168, {isa::op::TAY, isa::mode::I}}, + {169, {isa::op::LDA, isa::mode::IMM}}, + {170, {isa::op::TAX, isa::mode::I}}, + //{171, {isa::op::O_INVALID, isa::mode::M_INVALID}}, + {172, {isa::op::LDY, isa::mode::A}}, + {173, {isa::op::LDA, isa::mode::A}}, + {174, {isa::op::LDX, isa::mode::A}}, + {175, {isa::op::BBS2, isa::mode::R}}, + + {176, {isa::op::BCS, isa::mode::R}}, + {177, {isa::op::LDA, isa::mode::ZPIY}}, + {178, {isa::op::LDA, isa::mode::ZPI}}, + //{179, {isa::op::O_INVALID, isa::mode::M_INVALID}}, + {180, {isa::op::LDY, isa::mode::ZPX}}, + {181, {isa::op::LDA, isa::mode::ZPX}}, + {182, {isa::op::LDX, isa::mode::ZPY}}, + {183, {isa::op::SMB3, isa::mode::ZP}}, + {184, {isa::op::CLV, isa::mode::I}}, + {185, {isa::op::LDA, isa::mode::AIY}}, + {186, {isa::op::TSX, isa::mode::I}}, + //{187, {isa::op::O_INVALID, isa::mode::M_INVALID}}, + {188, {isa::op::LDY, isa::mode::AIX}}, + {189, {isa::op::LDA, isa::mode::AIX}}, + {190, {isa::op::LDX, isa::mode::AIY}}, + {191, {isa::op::BBS3, isa::mode::R}}, + + {192, {isa::op::CPY, isa::mode::IMM}}, + {193, {isa::op::CMP, isa::mode::ZPII}}, + //{194, {isa::op::O_INVALID, isa::mode::M_INVALID}}, + //{195, {isa::op::O_INVALID, isa::mode::M_INVALID}}, + {196, {isa::op::CPY, isa::mode::ZP}}, + {197, {isa::op::CMP, isa::mode::ZP}}, + {198, {isa::op::DEC, isa::mode::ZP}}, + {199, {isa::op::SMB4, isa::mode::ZP}}, + {200, {isa::op::INY, isa::mode::I}}, + {201, {isa::op::CMP, isa::mode::IMM}}, + {202, {isa::op::DEX, isa::mode::I}}, + {203, {isa::op::WAI, isa::mode::I}}, + {204, {isa::op::CPY, isa::mode::A}}, + {205, {isa::op::CMP, isa::mode::A}}, + {206, {isa::op::DEC, isa::mode::A}}, + {207, {isa::op::BBS4, isa::mode::R}}, + + {208, {isa::op::BNE, isa::mode::R}}, + {209, {isa::op::CMP, isa::mode::ZPIY}}, + {210, {isa::op::CMP, isa::mode::ZPI}}, + //{211, {isa::op::O_INVALID, isa::mode::M_INVALID}}, + //{212, {isa::op::O_INVALID, isa::mode::M_INVALID}}, + {213, {isa::op::CMP, isa::mode::ZPX}}, + {214, {isa::op::DEC, isa::mode::ZPX}}, + {215, {isa::op::SMB5, isa::mode::ZP}}, + {216, {isa::op::CLD, isa::mode::I}}, + {217, {isa::op::CMP, isa::mode::AIY}}, + {218, {isa::op::PHX, isa::mode::S}}, + {219, {isa::op::STP, isa::mode::I}}, + //{220, {isa::op::O_INVALID, isa::mode::M_INVALID}}, + {221, {isa::op::CMP, isa::mode::AIX}}, + {222, {isa::op::DEC, isa::mode::AIX}}, + {223, {isa::op::BBS5, isa::mode::R}}, + + {224, {isa::op::CPX, isa::mode::IMM}}, + {225, {isa::op::SBC, isa::mode::ZPII}}, + //{226, {isa::op::O_INVALID, isa::mode::M_INVALID}}, + //{227, {isa::op::O_INVALID, isa::mode::M_INVALID}}, + {228, {isa::op::CPX, isa::mode::ZP}}, + {229, {isa::op::SBC, isa::mode::ZP}}, + {230, {isa::op::INC, isa::mode::ZP}}, + {231, {isa::op::SMB6, isa::mode::ZP}}, + {232, {isa::op::INX, isa::mode::I}}, + {233, {isa::op::SBC, isa::mode::IMM}}, + {234, {isa::op::NOP, isa::mode::I}}, + //{235, {isa::op::O_INVALID, isa::mode::M_INVALID}}, + {236, {isa::op::CPX, isa::mode::A}}, + {237, {isa::op::SBC, isa::mode::A}}, + {238, {isa::op::INC, isa::mode::A}}, + {239, {isa::op::BBS6, isa::mode::R}}, + + {240, {isa::op::BEQ, isa::mode::R}}, + {241, {isa::op::SBC, isa::mode::ZPIY}}, + {242, {isa::op::SBC, isa::mode::ZPI}}, + //{243, {isa::op::O_INVALID, isa::mode::M_INVALID}}, + //{244, {isa::op::O_INVALID, isa::mode::M_INVALID}}, + {245, {isa::op::SBC, isa::mode::ZPX}}, + {246, {isa::op::INC, isa::mode::ZPX}}, + {247, {isa::op::SMB7, isa::mode::ZP}}, + {248, {isa::op::SED, isa::mode::I}}, + {249, {isa::op::SBC, isa::mode::AIY}}, + {250, {isa::op::PLX, isa::mode::S}}, + //{251, {isa::op::O_INVALID, isa::mode::M_INVALID}}, + //{252, {isa::op::O_INVALID, isa::mode::M_INVALID}}, + {253, {isa::op::SBC, isa::mode::AIX}}, + {254, {isa::op::INC, isa::mode::AIX}}, + {255, {isa::op::BBS7, isa::mode::R}}, + }; + return _; + } +} diff --git a/codec.hh b/codec.hh new file mode 100644 index 0000000..1fec841 --- /dev/null +++ b/codec.hh @@ -0,0 +1,12 @@ +#pragma once + +#include +#include +#include + +#include "isa.hh" + +namespace codec { + extern const std::map, uint8_t>& encode(); + const std::map>& decode(); +} diff --git a/field.hh b/field.hh new file mode 100644 index 0000000..e69de29 diff --git a/fromstring.cc b/fromstring.cc new file mode 100644 index 0000000..063ffb5 --- /dev/null +++ b/fromstring.cc @@ -0,0 +1,133 @@ +#include +#include + +#include "isa.hh" +#include "mneumonic.hh" + +namespace fromstring { + const std::unordered_map& op() { + static const std::unordered_map _ = { + {mneumonic::op::ADC, isa::op::ADC}, + {mneumonic::op::AND, isa::op::AND}, + {mneumonic::op::ASL, isa::op::ASL}, + {mneumonic::op::BBR0, isa::op::BBR0}, + {mneumonic::op::BBR1, isa::op::BBR1}, + {mneumonic::op::BBR2, isa::op::BBR2}, + {mneumonic::op::BBR3, isa::op::BBR3}, + {mneumonic::op::BBR4, isa::op::BBR4}, + {mneumonic::op::BBR5, isa::op::BBR5}, + {mneumonic::op::BBR6, isa::op::BBR6}, + {mneumonic::op::BBR7, isa::op::BBR7}, + {mneumonic::op::BBS0, isa::op::BBS0}, + {mneumonic::op::BBS1, isa::op::BBS1}, + {mneumonic::op::BBS2, isa::op::BBS2}, + {mneumonic::op::BBS3, isa::op::BBS3}, + {mneumonic::op::BBS4, isa::op::BBS4}, + {mneumonic::op::BBS5, isa::op::BBS5}, + {mneumonic::op::BBS6, isa::op::BBS6}, + {mneumonic::op::BBS7, isa::op::BBS7}, + {mneumonic::op::BCC, isa::op::BCC}, + {mneumonic::op::BCS, isa::op::BCS}, + {mneumonic::op::BEQ, isa::op::BEQ}, + {mneumonic::op::BIT, isa::op::BIT}, + {mneumonic::op::BMI, isa::op::BMI}, + {mneumonic::op::BNE, isa::op::BNE}, + {mneumonic::op::BPL, isa::op::BPL}, + {mneumonic::op::BRA, isa::op::BRA}, + {mneumonic::op::BRK, isa::op::BRK}, + {mneumonic::op::BVC, isa::op::BVC}, + {mneumonic::op::BVS, isa::op::BVS}, + {mneumonic::op::CLC, isa::op::CLC}, + {mneumonic::op::CLD, isa::op::CLD}, + {mneumonic::op::CLI, isa::op::CLI}, + {mneumonic::op::CLV, isa::op::CLV}, + {mneumonic::op::CMP, isa::op::CMP}, + {mneumonic::op::CPX, isa::op::CPX}, + {mneumonic::op::CPY, isa::op::CPY}, + {mneumonic::op::DEC, isa::op::DEC}, + {mneumonic::op::DEX, isa::op::DEX}, + {mneumonic::op::DEY, isa::op::DEY}, + {mneumonic::op::EOR, isa::op::EOR}, + {mneumonic::op::INC, isa::op::INC}, + {mneumonic::op::INX, isa::op::INX}, + {mneumonic::op::INY, isa::op::INY}, + {mneumonic::op::JMP, isa::op::JMP}, + {mneumonic::op::JSR, isa::op::JSR}, + {mneumonic::op::LDA, isa::op::LDA}, + {mneumonic::op::LDX, isa::op::LDX}, + {mneumonic::op::LDY, isa::op::LDY}, + {mneumonic::op::LSR, isa::op::LSR}, + {mneumonic::op::NOP, isa::op::NOP}, + {mneumonic::op::ORA, isa::op::ORA}, + {mneumonic::op::PHA, isa::op::PHA}, + {mneumonic::op::PHP, isa::op::PHP}, + {mneumonic::op::PHX, isa::op::PHX}, + {mneumonic::op::PHY, isa::op::PHY}, + {mneumonic::op::PLA, isa::op::PLA}, + {mneumonic::op::PLP, isa::op::PLP}, + {mneumonic::op::PLX, isa::op::PLX}, + {mneumonic::op::PLY, isa::op::PLY}, + {mneumonic::op::RMB0, isa::op::RMB0}, + {mneumonic::op::RMB1, isa::op::RMB1}, + {mneumonic::op::RMB2, isa::op::RMB2}, + {mneumonic::op::RMB3, isa::op::RMB3}, + {mneumonic::op::RMB4, isa::op::RMB4}, + {mneumonic::op::RMB5, isa::op::RMB5}, + {mneumonic::op::RMB6, isa::op::RMB6}, + {mneumonic::op::RMB7, isa::op::RMB7}, + {mneumonic::op::ROL, isa::op::ROL}, + {mneumonic::op::ROR, isa::op::ROR}, + {mneumonic::op::RTI, isa::op::RTI}, + {mneumonic::op::RTS, isa::op::RTS}, + {mneumonic::op::SBC, isa::op::SBC}, + {mneumonic::op::SEC, isa::op::SEC}, + {mneumonic::op::SED, isa::op::SED}, + {mneumonic::op::SEI, isa::op::SEI}, + {mneumonic::op::SMB0, isa::op::SMB0}, + {mneumonic::op::SMB1, isa::op::SMB1}, + {mneumonic::op::SMB2, isa::op::SMB2}, + {mneumonic::op::SMB3, isa::op::SMB3}, + {mneumonic::op::SMB4, isa::op::SMB4}, + {mneumonic::op::SMB5, isa::op::SMB5}, + {mneumonic::op::SMB6, isa::op::SMB6}, + {mneumonic::op::SMB7, isa::op::SMB7}, + {mneumonic::op::STA, isa::op::STA}, + {mneumonic::op::STP, isa::op::STP}, + {mneumonic::op::STX, isa::op::STX}, + {mneumonic::op::STY, isa::op::STY}, + {mneumonic::op::STZ, isa::op::STZ}, + {mneumonic::op::TAX, isa::op::TAX}, + {mneumonic::op::TAY, isa::op::TAY}, + {mneumonic::op::TRB, isa::op::TRB}, + {mneumonic::op::TSB, isa::op::TSB}, + {mneumonic::op::TSX, isa::op::TSX}, + {mneumonic::op::TXA, isa::op::TXA}, + {mneumonic::op::TXS, isa::op::TXS}, + {mneumonic::op::TYA, isa::op::TYA}, + {mneumonic::op::WAI, isa::op::WAI}, + }; + return _; + } + + const std::unordered_map& mode() { + static const std::unordered_map _ { + {mneumonic::mode::A, isa::mode::A}, + {mneumonic::mode::AII, isa::mode::AII}, + {mneumonic::mode::AIX, isa::mode::AIX}, + {mneumonic::mode::AIY, isa::mode::AIY}, + {mneumonic::mode::AI, isa::mode::AI}, + {mneumonic::mode::ACC, isa::mode::ACC}, + {mneumonic::mode::IMM, isa::mode::IMM}, + {mneumonic::mode::I, isa::mode::I}, + {mneumonic::mode::R, isa::mode::R}, + {mneumonic::mode::S, isa::mode::S}, + {mneumonic::mode::ZP, isa::mode::ZP}, + {mneumonic::mode::ZPII, isa::mode::ZPII}, + {mneumonic::mode::ZPX, isa::mode::ZPX}, + {mneumonic::mode::ZPY, isa::mode::ZPY}, + {mneumonic::mode::ZPI, isa::mode::ZPI}, + {mneumonic::mode::ZPIY, isa::mode::ZPIY}, + }; + return _; + } +} diff --git a/fromstring.hh b/fromstring.hh new file mode 100644 index 0000000..abaee46 --- /dev/null +++ b/fromstring.hh @@ -0,0 +1,14 @@ +#pragma once + +#include +#include + +#include "isa.hh" +#include "codec.hh" +#include "mneumonic.hh" + +namespace fromstring { + const std::unordered_map& op(); + + const std::unordered_map& mode(); +} diff --git a/isa.hh b/isa.hh new file mode 100644 index 0000000..9ed09cc --- /dev/null +++ b/isa.hh @@ -0,0 +1,125 @@ +#pragma once + +namespace isa { + +enum class op { + ADC, + AND, + ASL, + BBR0, + BBR1, + BBR2, + BBR3, + BBR4, + BBR5, + BBR6, + BBR7, + BBS0, + BBS1, + BBS2, + BBS3, + BBS4, + BBS5, + BBS6, + BBS7, + BCC, + BCS, + BEQ, + BIT, + BMI, + BNE, + BPL, + BRA, + BRK, + BVC, + BVS, + CLC, + CLD, + CLI, + CLV, + CMP, + CPX, + CPY, + DEC, + DEX, + DEY, + EOR, + INC, + INX, + INY, + JMP, + JSR, + LDA, + LDX, + LDY, + LSR, + NOP, + ORA, + PHA, + PHP, + PHX, + PHY, + PLA, + PLP, + PLX, + PLY, + RMB0, + RMB1, + RMB2, + RMB3, + RMB4, + RMB5, + RMB6, + RMB7, + ROL, + ROR, + RTI, + RTS, + SBC, + SEC, + SED, + SEI, + SMB0, + SMB1, + SMB2, + SMB3, + SMB4, + SMB5, + SMB6, + SMB7, + STA, + STP, + STX, + STY, + STZ, + TAX, + TAY, + TRB, + TSB, + TSX, + TXA, + TXS, + TYA, + WAI, +}; + +enum class mode { + A, // Absolute a + AII, // Absolute Indexed Indirect (a,x) + AIX, // Absolute Indexed with X a,x + AIY, // Absolute Indexed with Y a,y + AI, // Absolute Indrect (a) + ACC, // Accumulator A + IMM, // Immediate # + I, // Implied i + R, // Program Counter Relative r + S, // Stack s + ZP, // Zero Page zp + ZPII, // Zero Page Indexed Indirect (zp,x) + ZPX, // Zero Page Indexed with X zp,x + ZPY, // Zero Page Indexed with Y zp,y + ZPI, // Zero Page Indirect (zp) + ZPIY, // Zero Page Indirect Indexed with Y (zp),y +}; + +} diff --git a/main.cc b/main.cc new file mode 100644 index 0000000..71b7297 --- /dev/null +++ b/main.cc @@ -0,0 +1,137 @@ +#include +#include +#include +#include + +#include "assembler.hh" +#include "addressing_mode.hh" +#include "codec.hh" +#include "parser.hh" + +using symbol_table_t = std::unordered_map; + +bool resolve_symbols(assembler::program_t& program, symbol_table_t& symbol_table) +{ + size_t offset = 0; + + for (auto ins = program.begin(); ins != program.end(); ins++) { + if (ins->symbol != std::nullopt) { + auto [_, ok] = symbol_table.insert({*(ins->symbol), ins}); + if (!ok) { + std::cout << "duplicate symbol\n"; + return false; + } + + std::cout << *(ins->symbol) << ' ' << offset << '\n'; + } + + ins->location = offset; + + auto am_it = addressing_mode().find(ins->mode); + assert (am_it != addressing_mode().end()); + offset += 1 + am_it->second.len; + } + + return true; +} + +void serialize_program(const assembler::program_t& program, const symbol_table_t &symbol_table, size_t link_location, std::ostream& out) +{ + char buf[3]; + + for (auto ins = program.cbegin(); ins != program.cend(); ins++) { + std::cerr << "enc " << (int)ins->op << ' ' << (int)ins->mode << '\n'; + auto opcode_it = codec::encode().find({ins->op, ins->mode}); + assert (opcode_it != codec::encode().end()); + + buf[0] = opcode_it->second; + + auto am_it = addressing_mode().find(ins->mode); + assert (am_it != addressing_mode().end()); + + auto get_value = [&]() -> ssize_t { + if (std::holds_alternative(ins->value)) { + assembler::reference_t ref = std::get(ins->value); + auto sym_it = symbol_table.find(ref.symbol); + assert (sym_it != symbol_table.end()); + auto ref_ins = sym_it->second; + if (ins->mode == isa::mode::R) { + std::cout << "relative\n"; + ssize_t offset = static_cast(ref_ins->location) - static_cast(ins->location + 2); + return offset; + } else { + return ref_ins->location + link_location; + } + } else if (std::holds_alternative(ins->value)) { + assembler::literal_t lit = std::get(ins->value); + return lit.num; + } else if (std::holds_alternative(ins->value)) { + assert (std::holds_alternative(ins->value)); + } else { + assert (false); + } + return 0; + }; + + size_t value = get_value(); + if (!am_it->second.valid(value)) { + std::cout << "overflow at h" << std::hex << ins->location << '\n'; + } + + std::cout << "value " << std::hex << value << ' ' << am_it->second.len << '\n'; + + if (am_it->second.len >= 2) + buf[2] = (value >> 8) & 0xff; + if (am_it->second.len >= 1) + buf[1] = (value >> 0) & 0xff; + + out.write(buf, 1 + am_it->second.len); + } +} + +int main(int argc, char * argv[]) +{ + if (argc < 3) { + std::cerr << "argc < 3\n"; + return -1; + } + + std::string input_filename {argv[1]}; + std::ifstream is {input_filename, std::ios::binary | std::ios::ate}; + if (!is.is_open()) { + std::cerr << "failed to open " << input_filename << '\n'; + return -1; + } + + auto size = is.tellg(); + std::string buf(size, '\0'); // construct string to stream size + is.seekg(0); + is.read(buf.data(), size); + is.close(); + + + assembler::program_t program; + symbol_table_t symbol_table; + bool ok; + + ok = parser::parse(buf, program); + if (!ok) + return -1; + + ok = resolve_symbols(program, symbol_table); + if (!ok) + return -1; + + + std::string output_filename {argv[2]}; + std::ofstream out {output_filename, std::ios::binary}; + if (!out.is_open()) { + std::cerr << "failed to open " << output_filename << '\n'; + return -1; + } + + serialize_program(program, symbol_table, 0x8000, out); + + out.close(); + return 0; +} diff --git a/mneumonic.hh b/mneumonic.hh new file mode 100644 index 0000000..a371a16 --- /dev/null +++ b/mneumonic.hh @@ -0,0 +1,127 @@ +#pragma once + +#include + +namespace mneumonic { + namespace mode { + constexpr std::string_view A = "a"; + constexpr std::string_view AII = "(a,x)"; + constexpr std::string_view AIX = "a,x"; + constexpr std::string_view AIY = "a,y"; + constexpr std::string_view AI = "(a)"; + constexpr std::string_view ACC = "A"; + constexpr std::string_view IMM = "#"; + constexpr std::string_view I = "i"; + constexpr std::string_view R = "r"; + constexpr std::string_view S = "s"; + constexpr std::string_view ZP = "zp"; + constexpr std::string_view ZPII = "(zp,x)"; + constexpr std::string_view ZPX = "zp,x"; + constexpr std::string_view ZPY = "zp,y"; + constexpr std::string_view ZPI = "(zp)"; + constexpr std::string_view ZPIY = "(zp),y"; + } +} + +namespace mneumonic { + namespace op { + constexpr std::string_view ADC = "ADC"; + constexpr std::string_view AND = "AND"; + constexpr std::string_view ASL = "ASL"; + constexpr std::string_view BBR0 = "BBR0"; + constexpr std::string_view BBR1 = "BBR1"; + constexpr std::string_view BBR2 = "BBR2"; + constexpr std::string_view BBR3 = "BBR3"; + constexpr std::string_view BBR4 = "BBR4"; + constexpr std::string_view BBR5 = "BBR5"; + constexpr std::string_view BBR6 = "BBR6"; + constexpr std::string_view BBR7 = "BBR7"; + constexpr std::string_view BBS0 = "BBS0"; + constexpr std::string_view BBS1 = "BBS1"; + constexpr std::string_view BBS2 = "BBS2"; + constexpr std::string_view BBS3 = "BBS3"; + constexpr std::string_view BBS4 = "BBS4"; + constexpr std::string_view BBS5 = "BBS5"; + constexpr std::string_view BBS6 = "BBS6"; + constexpr std::string_view BBS7 = "BBS7"; + constexpr std::string_view BCC = "BCC"; + constexpr std::string_view BCS = "BCS"; + constexpr std::string_view BEQ = "BEQ"; + constexpr std::string_view BIT = "BIT"; + constexpr std::string_view BMI = "BMI"; + constexpr std::string_view BNE = "BNE"; + constexpr std::string_view BPL = "BPL"; + constexpr std::string_view BRA = "BRA"; + constexpr std::string_view BRK = "BRK"; + constexpr std::string_view BVC = "BVC"; + constexpr std::string_view BVS = "BVS"; + constexpr std::string_view CLC = "CLC"; + constexpr std::string_view CLD = "CLD"; + constexpr std::string_view CLI = "CLI"; + constexpr std::string_view CLV = "CLV"; + constexpr std::string_view CMP = "CMP"; + constexpr std::string_view CPX = "CPX"; + constexpr std::string_view CPY = "CPY"; + constexpr std::string_view DEC = "DEC"; + constexpr std::string_view DEX = "DEX"; + constexpr std::string_view DEY = "DEY"; + constexpr std::string_view EOR = "EOR"; + constexpr std::string_view INC = "INC"; + constexpr std::string_view INX = "INX"; + constexpr std::string_view INY = "INY"; + constexpr std::string_view JMP = "JMP"; + constexpr std::string_view JSR = "JSR"; + constexpr std::string_view LDA = "LDA"; + constexpr std::string_view LDX = "LDX"; + constexpr std::string_view LDY = "LDY"; + constexpr std::string_view LSR = "LSR"; + constexpr std::string_view NOP = "NOP"; + constexpr std::string_view ORA = "ORA"; + constexpr std::string_view PHA = "PHA"; + constexpr std::string_view PHP = "PHP"; + constexpr std::string_view PHX = "PHX"; + constexpr std::string_view PHY = "PHY"; + constexpr std::string_view PLA = "PLA"; + constexpr std::string_view PLP = "PLP"; + constexpr std::string_view PLX = "PLX"; + constexpr std::string_view PLY = "PLY"; + constexpr std::string_view RMB0 = "RMB0"; + constexpr std::string_view RMB1 = "RMB1"; + constexpr std::string_view RMB2 = "RMB2"; + constexpr std::string_view RMB3 = "RMB3"; + constexpr std::string_view RMB4 = "RMB4"; + constexpr std::string_view RMB5 = "RMB5"; + constexpr std::string_view RMB6 = "RMB6"; + constexpr std::string_view RMB7 = "RMB7"; + constexpr std::string_view ROL = "ROL"; + constexpr std::string_view ROR = "ROR"; + constexpr std::string_view RTI = "RTI"; + constexpr std::string_view RTS = "RTS"; + constexpr std::string_view SBC = "SBC"; + constexpr std::string_view SEC = "SEC"; + constexpr std::string_view SED = "SED"; + constexpr std::string_view SEI = "SEI"; + constexpr std::string_view SMB0 = "SMB0"; + constexpr std::string_view SMB1 = "SMB1"; + constexpr std::string_view SMB2 = "SMB2"; + constexpr std::string_view SMB3 = "SMB3"; + constexpr std::string_view SMB4 = "SMB4"; + constexpr std::string_view SMB5 = "SMB5"; + constexpr std::string_view SMB6 = "SMB6"; + constexpr std::string_view SMB7 = "SMB7"; + constexpr std::string_view STA = "STA"; + constexpr std::string_view STP = "STP"; + constexpr std::string_view STX = "STX"; + constexpr std::string_view STY = "STY"; + constexpr std::string_view STZ = "STZ"; + constexpr std::string_view TAX = "TAX"; + constexpr std::string_view TAY = "TAY"; + constexpr std::string_view TRB = "TRB"; + constexpr std::string_view TSB = "TSB"; + constexpr std::string_view TSX = "TSX"; + constexpr std::string_view TXA = "TXA"; + constexpr std::string_view TXS = "TXS"; + constexpr std::string_view TYA = "TYA"; + constexpr std::string_view WAI = "WAI"; + } +} diff --git a/parser.cc b/parser.cc new file mode 100644 index 0000000..08b199c --- /dev/null +++ b/parser.cc @@ -0,0 +1,261 @@ +#include +#include +#include +#include +#include + +#include "assembler.hh" +#include "addressing_mode.hh" +#include "fromstring.hh" +#include "isa.hh" + +static bool tokenize(std::string_view buf, std::function cb) +{ + auto it = buf.cbegin(); + std::optional token_begin = std::nullopt; + + ssize_t row = 0; + ssize_t col = 0; + + while (it != buf.cend()) { + auto c = *it; + switch (c) { + case '\n': + case ' ': + if (token_begin != std::nullopt) { + bool ret = cb(buf.substr(*token_begin - buf.cbegin(), it - *token_begin), row, col); + if (!ret) { + // cb failed + return false; + } + token_begin = std::nullopt; + } + break; + default: + if (token_begin == std::nullopt) { + token_begin = it; + } + break; + } + + if (c == '\n') { + col = 0; + row++; + } else { + col++; + }; + it++; + } + + bool ret = cb("", row + 1, col); + if (!ret) { + // cb failed + return false; + } + + return true; +} + + +namespace parser { + enum class state { + label_or_op, + op, + mode, + value, + comment, + just_comment, + }; +} + +using symbol_strings_t = std::unordered_map; + +namespace parser { + +bool parse(std::string_view buf, assembler::program_t& program) +{ + size_t current_symbol = 0; + symbol_strings_t ss; + + parser::state state = parser::state::label_or_op; + + auto get_symbol = [&](std::string_view s) { + auto find = ss.find(s); + if (find == ss.end()) { + auto insert = ss.insert({s, current_symbol++}); + assert(insert.second); + return (insert.first)->second; + } else { + return find->second; + } + }; + + assembler::instruction_t current_instruction; + ssize_t current_row; + + bool inside_comment = false; + + bool parsed = tokenize(buf, [&](std::string_view s, ssize_t row, ssize_t col) -> bool { + while (true) { + switch (state) { + case parser::state::label_or_op: + { + current_row = row; + if (s.back() == ':') { + std::string_view key = s.substr(0, s.length() - 1); + auto symbol = get_symbol(key); + std::cout << "label `" << symbol << "`\n"; + current_instruction.symbol = symbol; + state = parser::state::op; + return true; + } else if (s.front() == ';') { + state = parser::state::just_comment; + continue; + } else if (s.empty()) { + // I hate myself for this dirty hack + return true; + } else { + current_instruction.symbol = std::nullopt; + [[fallthrough]]; + } + } + case parser::state::op: + { + assert(row == current_row); + auto op_it = fromstring::op().find(s); + if (op_it == fromstring::op().end()) { + std::cout << "invalid op `" << s << "`\n"; + return false; + } else { + current_instruction.op = op_it->second; + std::cout << "ok op `" << static_cast(op_it->second) << "`\n"; + } + state = parser::state::mode; + return true; + } + case parser::state::mode: + { + assert(row == current_row); + auto mode_it = fromstring::mode().find(s); + if (mode_it == fromstring::mode().end()) { + std::cout << "invalid mode `" << s << "`\n"; + return false; + } else { + current_instruction.mode = mode_it->second; + std::cout << "ok mode `" << static_cast(mode_it->second) << "`\n"; + } + state = parser::state::value; + return true; + } + case parser::state::value: + { + auto am_it = addressing_mode().find(current_instruction.mode); + assert(am_it != addressing_mode().end()); + if (am_it->second.len == 0) { + std::cout << "no value expected\n"; + assembler::implied_t i {}; + current_instruction.value = i; + state = parser::state::comment; + continue; + } + + assert(row == current_row); + + auto parse_integer = [](std::string_view s, int base) -> std::optional { + std::string value_str {s.data() + 1, s.size() - 1}; + size_t pos; + ssize_t value; + value = std::stoll(value_str, &pos, base); + if (pos != value_str.length()) + return std::nullopt; + else + return value; + }; + + std::optional literal; + auto as_literal = [](ssize_t n) -> assembler::literal_t { return {n}; }; + switch (*s.cbegin()) { + case 'h': + { + literal = parse_integer(s, 16); + if (literal == std::nullopt) { + std::cout << "invalid hex literal\n"; + } + current_instruction.value = as_literal(*literal); + std::cout << "value hex literal `" << *literal << "`\n"; + break; + } + case 'd': + { + literal = parse_integer(s, 10); + if (literal == std::nullopt) { + std::cout << "invalid dec literal\n"; + return false; + } + current_instruction.value = as_literal(*literal); + std::cout << "value dec literal `" << *literal << "`\n"; + break; + } + case ':': + { + std::string_view key = s.substr(1, s.length() - 1); + assembler::reference_t reference = { get_symbol(key) }; + current_instruction.value = reference; + std::cout << "value reference `" << reference.symbol << "`\n"; + break; + } + default: + std::cout << "invalid base\n"; + return false; + } + + state = parser::state::comment; + return true; + } + case parser::state::comment: + { + if (row != current_row) { + std::cerr << "push " << (int)current_instruction.op << '\n'; + inside_comment = false; + program.push_back(current_instruction); + state = parser::state::label_or_op; + continue; + } + + if (*s.cbegin() == ';') { + inside_comment = true; + return true; + } else if (inside_comment) { + return true; + } else { + std::cout << "expected comment\n"; + return false; + } + } + case parser::state::just_comment: + { + if (row != current_row) { + inside_comment = false; + state = parser::state::label_or_op; + continue; + } + + if (*s.cbegin() == ';') { + inside_comment = true; + return true; + } else if (inside_comment) { + return true; + } else { + std::cout << "expected comment\n"; + return false; + } + } + } + } + return true; + }); + + return parsed; +} + +} diff --git a/parser.hh b/parser.hh new file mode 100644 index 0000000..e7abcd3 --- /dev/null +++ b/parser.hh @@ -0,0 +1,9 @@ +#pragma once + +#include + +#include "assembler.hh" + +namespace parser { + bool parse(std::string_view buf, assembler::program_t& program); +} diff --git a/tostring.cc b/tostring.cc new file mode 100644 index 0000000..b5e84a4 --- /dev/null +++ b/tostring.cc @@ -0,0 +1,127 @@ +#include +#include + +#include "instruction.hh" +#include "mneumonic.hh" + +namespace tostring { + const std::unordered_map op { + {op::ADC, mneumonic::op::ADC}, + {op::AND, mneumonic::op::AND}, + {op::ASL, mneumonic::op::ASL}, + {op::BBR0, mneumonic::op::BBR0}, + {op::BBR1, mneumonic::op::BBR1}, + {op::BBR2, mneumonic::op::BBR2}, + {op::BBR3, mneumonic::op::BBR3}, + {op::BBR4, mneumonic::op::BBR4}, + {op::BBR5, mneumonic::op::BBR5}, + {op::BBR6, mneumonic::op::BBR6}, + {op::BBR7, mneumonic::op::BBR7}, + {op::BBS0, mneumonic::op::BBS0}, + {op::BBS1, mneumonic::op::BBS1}, + {op::BBS2, mneumonic::op::BBS2}, + {op::BBS3, mneumonic::op::BBS3}, + {op::BBS4, mneumonic::op::BBS4}, + {op::BBS5, mneumonic::op::BBS5}, + {op::BBS6, mneumonic::op::BBS6}, + {op::BBS7, mneumonic::op::BBS7}, + {op::BCC, mneumonic::op::BCC}, + {op::BCS, mneumonic::op::BCS}, + {op::BEQ, mneumonic::op::BEQ}, + {op::BIT, mneumonic::op::BIT}, + {op::BMI, mneumonic::op::BMI}, + {op::BNE, mneumonic::op::BNE}, + {op::BPL, mneumonic::op::BPL}, + {op::BRA, mneumonic::op::BRA}, + {op::BRK, mneumonic::op::BRK}, + {op::BVC, mneumonic::op::BVC}, + {op::BVS, mneumonic::op::BVS}, + {op::CLC, mneumonic::op::CLC}, + {op::CLD, mneumonic::op::CLD}, + {op::CLI, mneumonic::op::CLI}, + {op::CLV, mneumonic::op::CLV}, + {op::CMP, mneumonic::op::CMP}, + {op::CPX, mneumonic::op::CPX}, + {op::CPY, mneumonic::op::CPY}, + {op::DEC, mneumonic::op::DEC}, + {op::DEX, mneumonic::op::DEX}, + {op::DEY, mneumonic::op::DEY}, + {op::EOR, mneumonic::op::EOR}, + {op::INC, mneumonic::op::INC}, + {op::INX, mneumonic::op::INX}, + {op::INY, mneumonic::op::INY}, + {op::JMP, mneumonic::op::JMP}, + {op::JSR, mneumonic::op::JSR}, + {op::LDA, mneumonic::op::LDA}, + {op::LDX, mneumonic::op::LDX}, + {op::LDY, mneumonic::op::LDY}, + {op::LSR, mneumonic::op::LSR}, + {op::NOP, mneumonic::op::NOP}, + {op::ORA, mneumonic::op::ORA}, + {op::PHA, mneumonic::op::PHA}, + {op::PHP, mneumonic::op::PHP}, + {op::PHX, mneumonic::op::PHX}, + {op::PHY, mneumonic::op::PHY}, + {op::PLA, mneumonic::op::PLA}, + {op::PLP, mneumonic::op::PLP}, + {op::PLX, mneumonic::op::PLX}, + {op::PLY, mneumonic::op::PLY}, + {op::RMB0, mneumonic::op::RMB0}, + {op::RMB1, mneumonic::op::RMB1}, + {op::RMB2, mneumonic::op::RMB2}, + {op::RMB3, mneumonic::op::RMB3}, + {op::RMB4, mneumonic::op::RMB4}, + {op::RMB5, mneumonic::op::RMB5}, + {op::RMB6, mneumonic::op::RMB6}, + {op::RMB7, mneumonic::op::RMB7}, + {op::ROL, mneumonic::op::ROL}, + {op::ROR, mneumonic::op::ROR}, + {op::RTI, mneumonic::op::RTI}, + {op::RTS, mneumonic::op::RTS}, + {op::SBC, mneumonic::op::SBC}, + {op::SEC, mneumonic::op::SEC}, + {op::SED, mneumonic::op::SED}, + {op::SEI, mneumonic::op::SEI}, + {op::SMB0, mneumonic::op::SMB0}, + {op::SMB1, mneumonic::op::SMB1}, + {op::SMB2, mneumonic::op::SMB2}, + {op::SMB3, mneumonic::op::SMB3}, + {op::SMB4, mneumonic::op::SMB4}, + {op::SMB5, mneumonic::op::SMB5}, + {op::SMB6, mneumonic::op::SMB6}, + {op::SMB7, mneumonic::op::SMB7}, + {op::STA, mneumonic::op::STA}, + {op::STP, mneumonic::op::STP}, + {op::STX, mneumonic::op::STX}, + {op::STY, mneumonic::op::STY}, + {op::STZ, mneumonic::op::STZ}, + {op::TAX, mneumonic::op::TAX}, + {op::TAY, mneumonic::op::TAY}, + {op::TRB, mneumonic::op::TRB}, + {op::TSB, mneumonic::op::TSB}, + {op::TSX, mneumonic::op::TSX}, + {op::TXA, mneumonic::op::TXA}, + {op::TXS, mneumonic::op::TXS}, + {op::TYA, mneumonic::op::TYA}, + {op::WAI, mneumonic::op::WAI}, + }; + + const std::unordered_map mode { + {mode::A, mneumonic::mode::A}, + {mode::AII, mneumonic::mode::AII}, + {mode::AIX, mneumonic::mode::AIX}, + {mode::AIY, mneumonic::mode::AIY}, + {mode::AI, mneumonic::mode::AI}, + {mode::ACC, mneumonic::mode::ACC}, + {mode::IMM, mneumonic::mode::IMM}, + {mode::I, mneumonic::mode::I}, + {mode::R, mneumonic::mode::R}, + {mode::S, mneumonic::mode::S}, + {mode::ZP, mneumonic::mode::ZP}, + {mode::ZPII, mneumonic::mode::ZPII}, + {mode::ZPX, mneumonic::mode::ZPX}, + {mode::ZPY, mneumonic::mode::ZPY}, + {mode::ZPI, mneumonic::mode::ZPI}, + {mode::ZPIY, mneumonic::mode::ZPIY}, + }; +} diff --git a/tostring.hh b/tostring.hh new file mode 100644 index 0000000..a7200c0 --- /dev/null +++ b/tostring.hh @@ -0,0 +1,11 @@ +#include +#include + +#include "codec.hh" +#include "mneumonic.hh" + +namespace tostring { + extern const std::unordered_map op; + + extern const std::unordered_map mode; +}