meow.git

tables.c

espurr
/* meow - 6502 assembler
 * Copyright (C) 2024-2025 ArcNyxx
 * see LICENCE file for licensing information */

#include <ctype.h>
#include <string.h>
#include <stdint.h>

#include "meow.h"
#include "tables.h"

mne_t
mnemonic(char *str)
{
	if (strlen(str) != 3)
		return INVMNE;

	str[0] = toupper(str[0]);
	str[1] = toupper(str[1]);
	str[2] = toupper(str[2]);

	switch (str[0]) {
	case 'A':
		if (str[1] == 'D' && str[2] == 'C')
			return ADC;
		if (str[1] == 'N' && str[2] == 'D')
			return AND;
		if (str[1] == 'S' && str[2] == 'L')
			return ASL;
		return INVMNE;
	case 'B':
		if (str[1] == 'C' && str[2] == 'C')
			return BCC;
		if (str[1] == 'C' && str[2] == 'S')
			return BCS;
		if (str[1] == 'E' && str[2] == 'Q')
			return BEQ;
		if (str[1] == 'I' && str[2] == 'T')
			return BIT;
		if (str[1] == 'M' && str[2] == 'I')
			return BMI;
		if (str[1] == 'N' && str[2] == 'E')
			return BNE;
		if (str[1] == 'P' && str[2] == 'L')
			return BPL;
		if (str[1] == 'R' && str[2] == 'K')
			return BRK;
		if (str[1] == 'V' && str[2] == 'C')
			return BVC;
		if (str[1] == 'V' && str[2] == 'S')
			return BVS;
		return INVMNE;
	case 'C':
		if (str[1] == 'L' && str[2] == 'C')
			return CLC;
		if (str[1] == 'L' && str[2] == 'D')
			return CLD;
		if (str[1] == 'L' && str[2] == 'I')
			return CLI;
		if (str[1] == 'L' && str[2] == 'V')
			return CLV;
		if (str[1] == 'M' && str[2] == 'P')
			return CMP;
		if (str[1] == 'P' && str[2] == 'X')
			return CPX;
		if (str[1] == 'P' && str[2] == 'Y')
			return CPY;
		return INVMNE;
	case 'D':
		if (str[1] == 'E' && str[2] == 'C')
			return DEC;
		if (str[1] == 'E' && str[2] == 'X')
			return DEX;
		if (str[1] == 'E' && str[2] == 'Y')
			return DEY;
		return INVMNE;
	case 'E':
		if (str[1] == 'O' && str[2] == 'R')
			return EOR;
		return INVMNE;
	case 'I':
		if (str[1] == 'N' && str[2] == 'C')
			return INC;
		if (str[1] == 'N' && str[2] == 'X')
			return INX;
		if (str[1] == 'N' && str[2] == 'Y')
			return INY;
		return INVMNE;
	case 'J':
		if (str[1] == 'M' && str[2] == 'P')
			return JMP;
		if (str[1] == 'S' && str[2] == 'R')
			return JSR;
		return INVMNE;
	case 'L':
		if (str[1] == 'D' && str[2] == 'A')
			return LDA;
		if (str[1] == 'D' && str[2] == 'X')
			return LDX;
		if (str[1] == 'D' && str[2] == 'Y')
			return LDY;
		if (str[1] == 'S' && str[2] == 'R')
			return LSR;
		return INVMNE;
	case 'N':
		if (str[1] == 'O' && str[2] == 'P')
			return NOP;
		return INVMNE;
	case 'O':
		if (str[1] == 'R' && str[2] == 'A')
			return ORA;
		return INVMNE;
	case 'P':
		if (str[1] == 'H' && str[2] == 'A')
			return PHA;
		if (str[1] == 'H' && str[2] == 'P')
			return PHP;
		if (str[1] == 'L' && str[2] == 'A')
			return PLA;
		if (str[1] == 'L' && str[2] == 'P')
			return PLP;
		return INVMNE;
	case 'R':
		if (str[1] == 'O' && str[2] == 'L')
			return ROL;
		if (str[1] == 'O' && str[2] == 'R')
			return ROR;
		if (str[1] == 'T' && str[2] == 'I')
			return RTI;
		if (str[1] == 'T' && str[2] == 'S')
			return RTS;
		return INVMNE;
	case 'S':
		if (str[1] == 'B' && str[2] == 'C')
			return SBC;
		if (str[1] == 'E' && str[2] == 'C')
			return SEC;
		if (str[1] == 'E' && str[2] == 'D')
			return SED;
		if (str[1] == 'E' && str[2] == 'I')
			return SEI;
		if (str[1] == 'T' && str[2] == 'A')
			return STA;
		if (str[1] == 'T' && str[2] == 'X')
			return STX;
		if (str[1] == 'T' && str[2] == 'Y')
			return STY;
		return INVMNE;
	case 'T':
		if (str[1] == 'A' && str[2] == 'X')
			return TAX;
		if (str[1] == 'A' && str[2] == 'Y')
			return TAY;
		if (str[1] == 'S' && str[2] == 'X')
			return TSX;
		if (str[1] == 'X' && str[2] == 'A')
			return TXA;
		if (str[1] == 'X' && str[2] == 'S')
			return TXS;
		if (str[1] == 'Y' && str[2] == 'A')
			return TYA;
		return INVMNE;
	default:
		return INVMNE;
	}
}

uint8_t
opcode(mne_t mne, addr_t addr)
{
	switch (mne) {
	case ADC:
		switch (addr) {
		case ABS:
			return 0x6d;
		case ABSX:
			return 0x7d;
		case ABSY:
			return 0x79;
		case IMM:
			return 0x69;
		case ZP:
			return 0x65;
		case ZPX:
			return 0x75;
		case ZPXI:
			return 0x61;
		case ZPYI:
			return 0x71;
		default:
			return 0xff;
		}
	case AND:
		switch (addr) {
		case ABS:
			return 0x2d;
		case ABSX:
			return 0x3d;
		case ABSY:
			return 0x39;
		case IMM:
			return 0x29;
		case ZP:
			return 0x25;
		case ZPX:
			return 0x35;
		case ZPXI:
			return 0x21;
		case ZPYI:
			return 0x31;
		default:
			return 0xff;
		}
	case ASL:
		switch (addr) {
		case ABS:
			return 0x0e;
		case ABSX:
			return 0x1e;
		case IMP:
			return 0x0a;
		case ZP:
			return 0x06;
		case ZPX:
			return 0x16;
		default:
			return 0xff;
		}
	case BCC:
		switch (addr) {
		case REL:
			return 0x90;
		default:
			return 0xff;
		}
	case BCS:
		switch (addr) {
		case REL:
			return 0xb0;
		default:
			return 0xff;
		}
	case BEQ:
		switch (addr) {
		case REL:
			return 0xf0;
		default:
			return 0xff;
		}
	case BIT:
		switch (addr) {
		case ABS:
			return 0x2c;
		case IMM:
			return 0x89;
		case ZP:
			return 0x24;
		default:
			return 0xff;
		}
	case BMI:
		switch (addr) {
		case REL:
			return 0x30;
		default:
			return 0xff;
		}
	case BNE:
		switch (addr) {
		case REL:
			return 0xd0;
		default:
			return 0xff;
		}
	case BPL:
		switch (addr) {
		case REL:
			return 0x10;
		default:
			return 0xff;
		}
	case BRK:
		switch (addr) {
		case IMP:
			return 0x00;
		default:
			return 0xff;
		}
	case BVC:
		switch (addr) {
		case REL:
			return 0x50;
		default:
			return 0xff;
		}
	case BVS:
		switch (addr) {
		case REL:
			return 0x70;
		default:
			return 0xff;
		}
	case CLC:
		switch (addr) {
		case IMP:
			return 0x18;
		default:
			return 0xff;
		}
	case CLD:
		switch (addr) {
		case IMP:
			return 0xd8;
		default:
			return 0xff;
		}
	case CLI:
		switch (addr) {
		case IMP:
			return 0x58;
		default:
			return 0xff;
		}
	case CLV:
		switch (addr) {
		case IMP:
			return 0xb8;
		default:
			return 0xff;
		}
	case CMP:
		switch (addr) {
		case ABS:
			return 0xcd;
		case ABSX:
			return 0xdd;
		case ABSY:
			return 0xd9;
		case IMM:
			return 0xc9;
		case ZP:
			return 0xc5;
		case ZPX:
			return 0xd5;
		case ZPXI:
			return 0xc1;
		case ZPYI:
			return 0xd1;
		default:
			return 0xff;
		}
	case CPX:
		switch (addr) {
		case ABS:
			return 0xec;
		case IMM:
			return 0xe0;
		case ZP:
			return 0xe4;
		default:
			return 0xff;
		}
	case CPY:
		switch (addr) {
		case ABS:
			return 0xcc;
		case IMM:
			return 0xc0;
		case ZP:
			return 0xc4;
		default:
			return 0xff;
		}
	case DEC:
		switch (addr) {
		case ABS:
			return 0xce;
		case ABSX:
			return 0xde;
		case ZP:
			return 0xc6;
		case ZPX:
			return 0xd6;
		default:
			return 0xff;
		}
	case DEX:
		switch (addr) {
		case IMP:
			return 0xca;
		default:
			return 0xff;
		}
	case DEY:
		switch (addr) {
		case IMP:
			return 0x88;
		default:
			return 0xff;
		}
	case EOR:
		switch (addr) {
		case ABS:
			return 0x4d;
		case ABSX:
			return 0x5d;
		case ABSY:
			return 0x59;
		case IMM:
			return 0x49;
		case ZP:
			return 0x45;
		case ZPX:
			return 0x55;
		case ZPXI:
			return 0x41;
		case ZPYI:
			return 0x51;
		default:
			return 0xff;
		}
	case INC:
		switch (addr) {
		case ABS:
			return 0xee;
		case ABSX:
			return 0xfe;
		case ZP:
			return 0xe6;
		case ZPX:
			return 0xf6;
		default:
			return 0xff;
		}
	case INX:
		switch (addr) {
		case IMP:
			return 0xe8;
		default:
			return 0xff;
		}
	case INY:
		switch (addr) {
		case IMP:
			return 0xc8;
		default:
			return 0xff;
		}
	case JMP:
		switch (addr) {
		case ABS:
			return 0x4c;
		case ABSI:
			return 0x6c;
		default:
			return 0xff;
		}
	case JSR:
		switch (addr) {
		case ABS:
			return 0x20;
		default:
			return 0xff;
		}
	case LDA:
		switch (addr) {
		case ABS:
			return 0xad;
		case ABSX:
			return 0xbd;
		case ABSY:
			return 0xb9;
		case IMM:
			return 0xa9;
		case ZP:
			return 0xa5;
		case ZPX:
			return 0xb5;
		case ZPXI:
			return 0xa1;
		case ZPYI:
			return 0xb1;
		default:
			return 0xff;
		}
	case LDX:
		switch (addr) {
		case ABS:
			return 0xae;
		case ABSY:
			return 0xbe;
		case IMM:
			return 0xa2;
		case ZP:
			return 0xa6;
		case ZPY:
			return 0xb6;
		default:
			return 0xff;
		}
	case LDY:
		switch (addr) {
		case ABS:
			return 0xac;
		case ABSX:
			return 0xbc;
		case IMM:
			return 0xa0;
		case ZP:
			return 0xa4;
		case ZPX:
			return 0xb4;
		default:
			return 0xff;
		}
	case LSR:
		switch (addr) {
		case ABS:
			return 0x4e;
		case ABSX:
			return 0x5e;
		case IMP:
			return 0x4a;
		case ZP:
			return 0x46;
		case ZPX:
			return 0x56;
		default:
			return 0xff;
		}
	case NOP:
		switch (addr) {
		case IMP:
			return 0xea;
		default:
			return 0xff;
		}
	case ORA:
		switch (addr) {
		case ABS:
			return 0x0d;
		case ABSX:
			return 0x1d;
		case ABSY:
			return 0x19;
		case IMM:
			return 0x09;
		case ZP:
			return 0x05;
		case ZPX:
			return 0x15;
		case ZPXI:
			return 0x01;
		case ZPYI:
			return 0x11;
		default:
			return 0xff;
		}
	case PHA:
		switch (addr) {
		case IMP:
			return 0x48;
		default:
			return 0xff;
		}
	case PHP:
		switch (addr) {
		case IMP:
			return 0x08;
		default:
			return 0xff;
		}
	case PLA:
		switch (addr) {
		case IMP:
			return 0x68;
		default:
			return 0xff;
		}
	case PLP:
		switch (addr) {
		case IMP:
			return 0x28;
		default:
			return 0xff;
		}
	case ROL:
		switch (addr) {
		case ABS:
			return 0x2e;
		case ABSX:
			return 0x3e;
		case IMP:
			return 0x2a;
		case ZP:
			return 0x26;
		case ZPX:
			return 0x36;
		default:
			return 0xff;
		}
	case ROR:
		switch (addr) {
		case ABS:
			return 0x6e;
		case ABSX:
			return 0x7e;
		case IMP:
			return 0x6a;
		case ZP:
			return 0x66;
		case ZPX:
			return 0x76;
		default:
			return 0xff;
		}
	case RTI:
		switch (addr) {
		case IMP:
			return 0x40;
		default:
			return 0xff;
		}
	case RTS:
		switch (addr) {
		case IMP:
			return 0x60;
		default:
			return 0xff;
		}
	case SBC:
		switch (addr) {
		case ABS:
			return 0xed;
		case ABSX:
			return 0xfd;
		case ABSY:
			return 0xf9;
		case IMM:
			return 0xe9;
		case ZP:
			return 0xe5;
		case ZPX:
			return 0xf5;
		case ZPXI:
			return 0xe1;
		case ZPYI:
			return 0xf1;
		default:
			return 0xff;
		}
	case SEC:
		switch (addr) {
		case IMP:
			return 0x38;
		default:
			return 0xff;
		}
	case SED:
		switch (addr) {
		case IMP:
			return 0xf8;
		default:
			return 0xff;
		}
	case SEI:
		switch (addr) {
		case IMP:
			return 0x78;
		default:
			return 0xff;
		}
	case STA:
		switch (addr) {
		case ABS:
			return 0x8d;
		case ABSX:
			return 0x9d;
		case ABSY:
			return 0x99;
		case ZP:
			return 0x85;
		case ZPX:
			return 0x95;
		case ZPXI:
			return 0x81;
		case ZPYI:
			return 0x91;
		default:
			return 0xff;
		}
	case STX:
		switch (addr) {
		case ABS:
			return 0x8e;
		case ZP:
			return 0x86;
		case ZPY:
			return 0x96;
		default:
			return 0xff;
		}
	case STY:
		switch (addr) {
		case ABS:
			return 0x8c;
		case ZP:
			return 0x84;
		case ZPX:
			return 0x94;
		default:
			return 0xff;
		}
	case TAX:
		switch (addr) {
		case IMP:
			return 0xaa;
		default:
			return 0xff;
		}
	case TAY:
		switch (addr) {
		case IMP:
			return 0xa8;
		default:
			return 0xff;
		}
	case TSX:
		switch (addr) {
		case IMP:
			return 0xba;
		default:
			return 0xff;
		}
	case TXA:
		switch (addr) {
		case IMP:
			return 0x8a;
		default:
			return 0xff;
		}
	case TXS:
		switch (addr) {
		case IMP:
			return 0x9a;
		default:
			return 0xff;
		}
	case TYA:
		switch (addr) {
		case IMP:
			return 0x98;
		default:
			return 0xff;
		}
	default:
		return 0xff;
	}
}