commit 8054ac43ac7fb8ef09934025f696d68932a6d38e Author: Zack Buhman Date: Sun Mar 20 15:50:14 2022 -0700 initial 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; +}