/*
 * A simple 6502 disassembler
 */

#include <stdio.h>
#include "disasm.h"

static unsigned char *buffer;
int ptr, len;

inline unsigned char nextbyte (void)
{
	if (ptr >= len)
	{
		printf ("Overflowing end of buffer.\n");
		return 0;
	}
	return buffer[ptr++];
}

#define ABS (nextbyte () | (nextbyte () << 8))
#define REL ((ptr + base_addr) + (signed char)(nextbyte ()))

inline char *disasm_instruc (void)
{
	static char buf[256];
	int i, b;
	
	switch (b = nextbyte ())
	{
		case 0x00:
		sprintf (buf, "brk");
		break;
		
		case 0x10:
		sprintf (buf, "bpl %s", find_symbol (i = REL, SYM_CODE));
		//sync_points[n_syncpts++] = i;
		break;
		
		case 0x20:
		sprintf (buf, "jsr %s", find_symbol (i = ABS, SYM_CODE));
		//sync_points[n_syncpts++] = i;
		break;
		
		case 0x30:
		sprintf (buf, "bmi %s", find_symbol (i = REL, SYM_CODE));
		//sync_points[n_syncpts++] = i;			
		break;
		
		case 0x40:
		sprintf (buf, "rti");
		break;
		
		case 0x50:
		sprintf (buf, "bvc %s", find_symbol (i = REL, SYM_CODE));
		//sync_points[n_syncpts++] = i;
		break;
		
		case 0x60:
		sprintf (buf, "rts");
		break;
		
		case 0x70:
		sprintf (buf, "bvs %s", find_symbol (i = REL, SYM_CODE));
		//sync_points[n_syncpts++] = i;
		break;
		
#ifdef CMOS
		case 0x80:
		sprintf (buf, "bra %s", find_symbol (i = REL, SYM_CODE));
		//sync_points[n_syncpts++] = i;
		break;
#endif
		
		case 0x90:
		sprintf (buf, "bcc %s", find_symbol (i = REL, SYM_CODE));
		//sync_points[n_syncpts++] = i;
		break;
		
		case 0xa0:
		sprintf (buf, "ldy #%s", hex (nextbyte ()));
		break;
		
		case 0xb0:
		sprintf (buf, "bcs %s", find_symbol (i = REL, SYM_CODE));
		//sync_points[n_syncpts++] = i;
		break;
		
		case 0xc0:
		sprintf (buf, "cpy #%s", hex (nextbyte ()));
		break;
		
		case 0xd0:
		sprintf (buf, "bne %s", find_symbol (i = REL, SYM_CODE));
		//sync_points[n_syncpts++] = i;
		break;
		
		case 0xe0:
		sprintf (buf, "cpx #%s", hex (nextbyte ()));
		break;
		
		case 0xf0:
		sprintf (buf, "beq %s", find_symbol (i = REL, SYM_CODE));
		//sync_points[n_syncpts++] = i;
		break;
		
		case 0x01:
		sprintf (buf, "ora (%s,X)", hex (nextbyte ()));
		break;
		
		case 0x11:
		sprintf (buf, "ora (%s),Y", hex (nextbyte ()));
		break;
		
		case 0x21:
		sprintf (buf, "and (%s,X)", hex (nextbyte ()));
		break;
		
		case 0x31:
		sprintf (buf, "and (%s),Y", hex (nextbyte ()));
		break;
		
		case 0x41:
		sprintf (buf, "eor (%s,X)", hex (nextbyte ()));
		break;
		
		case 0x51:
		sprintf (buf, "eor (%s),Y", hex (nextbyte ()));
		break;
		
		case 0x61:
		sprintf (buf, "adc (%s,X)", hex (nextbyte ()));
		break;
		
		case 0x71:
		sprintf (buf, "adc (%s),Y", hex (nextbyte ()));
		break;
		
		case 0x81:
		sprintf (buf, "sta (%s,X)", hex (nextbyte ()));
		break;
		
		case 0x91:
		sprintf (buf, "sta (%s),Y", hex (nextbyte ()));
		break;
		
		case 0xa1:
		sprintf (buf, "lda (%s,X)", hex (nextbyte ()));
		break;
		
		case 0xb1:
		sprintf (buf, "lda (%s),Y", hex (nextbyte ()));
		break;
		
		case 0xc1:
		sprintf (buf, "cmp (%s,X)", hex (nextbyte ()));
		break;
		
		case 0xd1:
		sprintf (buf, "cmp (%s),Y", hex (nextbyte ()));
		break;
		
		case 0xe1:
		sprintf (buf, "sbc (%s,X)", hex (nextbyte ()));
		break;
		
		case 0xf1:
		sprintf (buf, "sbc (%s),Y", hex (nextbyte ()));
		break;
		
#ifdef CMOS
		case 0x12:
		sprintf (buf, "ora (%s)", hex (nextbyte ()));
		break;
		
		case 0x32:
		sprintf (buf, "and (%s)", hex (nextbyte ()));
		break;
		
		case 0x52:
		sprintf (buf, "eor (%s)", hex (nextbyte ()));
		break;
		
		case 0x72:
		sprintf (buf, "adc (%s)", hex (nextbyte ()));
		break;
		
		case 0x92:
		sprintf (buf, "lda (%s)", hex (nextbyte ()));
		break;
#endif

		case 0xa2:
		sprintf (buf, "ldx #%s", hex (nextbyte ()));
		break;
		
#ifdef CMOS
		case 0xb2:
		sprintf (buf, "sta (%s)", hex (nextbyte ()));
		break;
		
		case 0xd2:
		sprintf (buf, "cmp (%s)", hex (nextbyte ()));
		break;
		
		case 0xf2:
		sprintf (buf, "sbc (%s)", hex (nextbyte ()));
		break;
		
		case 0x04:
		sprintf (buf, "tsb %s", hex (nextbyte ()));
		break;
		
		case 0x14:
		sprintf (buf, "trb %s", hex (nextbyte ()));
		break;
#endif
		
		case 0x24:
		sprintf (buf, "bit %s", hex (nextbyte ()));
		break;
		
#ifdef CMOS
		case 0x34:
		sprintf (buf, "bit %s,X", hex (nextbyte ()));
		break;
		
		case 0x64:
		sprintf (buf, "stz %s", hex (nextbyte ()));
		break;
		
		case 0x74:
		sprintf (buf, "stz %s,X", hex (nextbyte ()));
		break;
#endif
		
		case 0x84:
		sprintf (buf, "sty %s", hex (nextbyte ()));
		break;
		
		case 0x94:
		sprintf (buf, "sty %s,X", hex (nextbyte ()));
		break;
		
		case 0xa4:
		sprintf (buf, "ldy %s", hex (nextbyte ()));
		break;
		
		case 0xb4:
		sprintf (buf, "ldy %s,X", hex (nextbyte ()));
		break;
		
		case 0xc4:
		sprintf (buf, "cpy %s", hex (nextbyte ()));
		break;
		
		case 0xe4:
		sprintf (buf, "cpx %s", hex (nextbyte ()));
		break;
		
		case 0x05:
		sprintf (buf, "ora %s", hex (nextbyte ()));
		break;
		
		case 0x15:
		sprintf (buf, "ora %s,X", hex (nextbyte ()));
		break;
		
		case 0x25:
		sprintf (buf, "and %s", hex (nextbyte ()));
		break;
		
		case 0x35:
		sprintf (buf, "and %s,X", hex (nextbyte ()));
		break;
		
		case 0x45:
		sprintf (buf, "eor %s", hex (nextbyte ()));
		break;
		
		case 0x55:
		sprintf (buf, "eor %s,X", hex (nextbyte ()));
		break;
		
		case 0x65:
		sprintf (buf, "adc %s", hex (nextbyte ()));
		break;
		
		case 0x75:
		sprintf (buf, "adc %s,X", hex (nextbyte ()));
		break;
		
		case 0x85:
		sprintf (buf, "sta %s", hex (nextbyte ()));
		break;
		
		case 0x95:
		sprintf (buf, "sta %s,X", hex (nextbyte ()));
		break;
		
		case 0xa5:
		sprintf (buf, "lda %s", hex (nextbyte ()));
		break;
		
		case 0xb5:
		sprintf (buf, "lda %s,X", hex (nextbyte ()));
		break;
		
		case 0xc5:
		sprintf (buf, "cmp %s", hex (nextbyte ()));
		break;
		
		case 0xd5:
		sprintf (buf, "cmp %s,X", hex (nextbyte ()));
		break;
		
		case 0xe5:
		sprintf (buf, "sbc %s", hex (nextbyte ()));
		break;
		
		case 0xf5:
		sprintf (buf, "sbc %s,X", hex (nextbyte ()));
		break;
		
		case 0x06:
		sprintf (buf, "asl %s", hex (nextbyte ()));
		break;
		
		case 0x16:
		sprintf (buf, "asl %s,X", hex (nextbyte ()));
		break;
		
		case 0x26:
		sprintf (buf, "rol %s", hex (nextbyte ()));
		break;
		
		case 0x36:
		sprintf (buf, "rol %s,X", hex (nextbyte ()));
		break;
		
		case 0x46:
		sprintf (buf, "lsr %s", hex (nextbyte ()));
		break;
		
		case 0x56:
		sprintf (buf, "lsr %s,X", hex (nextbyte ()));
		break;
		
		case 0x66:
		sprintf (buf, "ror %s", hex (nextbyte ()));
		break;
		
		case 0x76:
		sprintf (buf, "ror %s,X", hex (nextbyte ()));
		break;
		
		case 0x86:
		sprintf (buf, "stx %s", hex (nextbyte ()));
		break;
		
		case 0x96:
		sprintf (buf, "stx %s,Y", hex (nextbyte ()));
		break;
		
		case 0xa6:
		sprintf (buf, "ldx %s", hex (nextbyte ()));
		break;
		
		case 0xb6:
		sprintf (buf, "ldx %s,Y", hex (nextbyte ()));
		break;
		
		case 0xc6:
		sprintf (buf, "dec %s", hex (nextbyte ()));
		break;
		
		case 0xd6:
		sprintf (buf, "dec %s,X", hex (nextbyte ()));
		break;
		
		case 0xe6:
		sprintf (buf, "inc %s", hex (nextbyte ()));
		break;
		
		case 0xf6:
		sprintf (buf, "inc %s,X", hex (nextbyte ()));
		break;
		
#ifdef CMOS
		case 0x07:
		case 0x17:
		case 0x27:
		case 0x37:
		case 0x47:
		case 0x57:
		case 0x67:
		case 0x77:
		sprintf (buf, "rmb%d %s", b & 0x07, hex (nextbyte ()));
		break;
		
		case 0x87:
		case 0x97:
		case 0xa7:
		case 0xb7:
		case 0xc7:
		case 0xd7:
		case 0xe7:
		case 0xf7:
		sprintf (buf, "smb%d %s", b & 0x07, hex (nextbyte ()));
		break;
#endif
		
		case 0x08:
		sprintf (buf, "php");
		break;
		
		case 0x18:
		sprintf (buf, "clc");
		break;
		
		case 0x28:
		sprintf (buf, "plp");
		break;
		
		case 0x38:
		sprintf (buf, "sec");
		break;
		
		case 0x48:
		sprintf (buf, "pha");
		break;
		
		case 0x58:
		sprintf (buf, "cli");
		break;
		
		case 0x68:
		sprintf (buf, "pla");
		break;
		
		case 0x78:
		sprintf (buf, "sei");
		break;
		
		case 0x88:
		sprintf (buf, "dey");
		break;
		
		case 0x98:
		sprintf (buf, "tya");
		break;
		
		case 0xa8:
		sprintf (buf, "tay");
		break;
		
		case 0xb8:
		sprintf (buf, "clv");
		break;
		
		case 0xc8:
		sprintf (buf, "iny");
		break;
		
		case 0xd8:
		sprintf (buf, "cld");
		break;
		
		case 0xe8:
		sprintf (buf, "inx");
		break;
		
		case 0xf8:
		sprintf (buf, "sed");
		break;
		
		case 0x09:
		sprintf (buf, "ora #%s", hex (nextbyte ()));
		break;
		
		case 0x19:
		sprintf (buf, "ora %s,Y", find_symbol (ABS, SYM_DATA));
		break;
		
		case 0x29:
		sprintf (buf, "and #%s", hex (nextbyte ()));
		break;
		
		case 0x39:
		sprintf (buf, "and %s,Y", find_symbol (ABS, SYM_DATA));
		break;
		
		case 0x49:
		sprintf (buf, "eor #%s", hex (nextbyte ()));
		break;
		
		case 0x59:
		sprintf (buf, "eor %s,Y", find_symbol (ABS, SYM_DATA));
		break;
		
		case 0x69:
		sprintf (buf, "adc #%s", hex (nextbyte ()));
		break;
		
		case 0x79:
		sprintf (buf, "adc %s,Y", find_symbol (ABS, SYM_DATA));
		break;
		
#ifdef CMOS
		case 0x89:
		sprintf (buf, "bit #%s", hex (nextbyte ()));
		break;
#endif
		
		case 0x99:
		sprintf (buf, "sta %s,Y", find_symbol (ABS, SYM_DATA));
		break;
		
		case 0xa9:
		sprintf (buf, "lda #%s", hex (nextbyte ()));
		break;
		
		case 0xb9:
		sprintf (buf, "lda %s,Y", find_symbol (ABS, SYM_DATA));
		break;
		
		case 0xc9:
		sprintf (buf, "cmp #%s", hex (nextbyte ()));
		break;
		
		case 0xd9:
		sprintf (buf, "cmp %s,Y", find_symbol (ABS, SYM_DATA));
		break;
		
		case 0xe9:
		sprintf (buf, "sbc #%s", hex (nextbyte ()));
		break;
		
		case 0xf9:
		sprintf (buf, "sbc %s,Y", find_symbol (ABS, SYM_DATA));
		break;
		
		case 0x0a:
		sprintf (buf, "asl A");
		break;
		
#ifdef CMOS
		case 0x1a:
		sprintf (buf, "inc A");
		break;
#endif
		
		case 0x2a:
		sprintf (buf, "rol A");
		break;
		
#ifdef CMOS
		case 0x3a:
		sprintf (buf, "dec A");
		break;
#endif
		
		case 0x4a:
		sprintf (buf, "lsr A");
		break;
		
#ifdef CMOS
		case 0x5a:
		sprintf (buf, "phy");
		break;
#endif
		
		case 0x6a:
		sprintf (buf, "ror A");
		break;
		
#ifdef CMOS
		case 0x7a:
		sprintf (buf, "ply");
		break;
#endif
		
		case 0x8a:
		sprintf (buf, "txa");
		break;
		
		case 0x9a:
		sprintf (buf, "txs");
		break;
		
		case 0xaa:
		sprintf (buf, "tax");
		break;
		
		case 0xba:
		sprintf (buf, "tsx");
		break;
		
		case 0xca:
		sprintf (buf, "dex");
		break;
		
#ifdef CMOS
		case 0xda:
		sprintf (buf, "phx");
		break;
#endif
		
		case 0xea:
		sprintf (buf, "nop");
		break;
		
#ifdef CMOS
		case 0xfa:
		sprintf (buf, "plx");
		break;
		
		case 0x0c:
		sprintf (buf, "tsb %s", find_symbol (ABS, SYM_DATA));
		break;
		
		case 0x1c:
		sprintf (buf, "trb %s", find_symbol (ABS, SYM_DATA));
		break;
#endif
		
		case 0x2c:
		sprintf (buf, "bit %s", find_symbol (ABS, SYM_DATA));
		break;
		
#ifdef CMOS
		case 0x3c:
		sprintf (buf, "bit %s,X", find_symbol (ABS, SYM_DATA));
		break;
#endif
		
		case 0x4c:
		sprintf (buf, "jmp %s", find_symbol (i = ABS, SYM_CODE));
		//sync_points[n_syncpts++] = i;
		break;
		
		case 0x6c:
		sprintf (buf, "jmp (%s)", find_symbol (ABS, SYM_CODE));
		break;
		
#ifdef CMOS
		case 0x7c:
		sprintf (buf, "jmp (%s,X)", find_symbol (ABS, SYM_CODE));
		break;
#endif
		
		case 0x8c:
		sprintf (buf, "sty %s", find_symbol (ABS, SYM_DATA));
		break;
		
#ifdef CMOS
		case 0x9c:
		sprintf (buf, "stz %s", find_symbol (ABS, SYM_DATA));
		break;
#endif
		
		case 0xac:
		sprintf (buf, "ldy %s", find_symbol (ABS, SYM_DATA));
		break;
		
		case 0xbc:
		sprintf (buf, "ldy %s,X", find_symbol (ABS, SYM_DATA));
		break;
		
		case 0xcc:
		sprintf (buf, "cpy %s", find_symbol (ABS, SYM_DATA));
		break;
		
		case 0xec:
		sprintf (buf, "cpx %s", find_symbol (ABS, SYM_DATA));
		break;
		
		case 0x0d:
		sprintf (buf, "ora %s", find_symbol (ABS, SYM_DATA));
		break;
		
		case 0x1d:
		sprintf (buf, "ora %s,X", find_symbol (ABS, SYM_DATA));
		break;
		
		case 0x2d:
		sprintf (buf, "and %s", find_symbol (ABS, SYM_DATA));
		break;
		
		case 0x3d:
		sprintf (buf, "and %s,X", find_symbol (ABS, SYM_DATA));
		break;
		
		case 0x4d:
		sprintf (buf, "eor %s", find_symbol (ABS, SYM_DATA));
		break;
		
		case 0x5d:
		sprintf (buf, "eor %s,X", find_symbol (ABS, SYM_DATA));
		break;
		
		case 0x6d:
		sprintf (buf, "adc %s", find_symbol (ABS, SYM_DATA));
		break;
		
		case 0x7d:
		sprintf (buf, "adc %s,X", find_symbol (ABS, SYM_DATA));
		break;
		
		case 0x8d:
		sprintf (buf, "sta %s", find_symbol (ABS, SYM_DATA));
		break;
		
		case 0x9d:
		sprintf (buf, "sta %s,X", find_symbol (ABS, SYM_DATA));
		break;
		
		case 0xad:
		sprintf (buf, "lda %s", find_symbol (ABS, SYM_DATA));
		break;
		
		case 0xbd:
		sprintf (buf, "lda %s,X", find_symbol (ABS, SYM_DATA));
		break;
		
		case 0xcd:
		sprintf (buf, "cmp %s", find_symbol (ABS, SYM_DATA));
		break;
		
		case 0xdd:
		sprintf (buf, "cmp %s,X", find_symbol (ABS, SYM_DATA));
		break;
		
		case 0xed:
		sprintf (buf, "sbc %s", find_symbol (ABS, SYM_DATA));
		break;
		
		case 0xfd:
		sprintf (buf, "sbc %s,X", find_symbol (ABS, SYM_DATA));
		break;
		
		case 0x0e:
		sprintf (buf, "asl %s", find_symbol (ABS, SYM_DATA));
		break;
		
		case 0x1e:
		sprintf (buf, "asl %s,X", find_symbol (ABS, SYM_DATA));
		break;
		
		case 0x2e:
		sprintf (buf, "rol %s", find_symbol (ABS, SYM_DATA));
		break;
		
		case 0x3e:
		sprintf (buf, "rol %s,X", find_symbol (ABS, SYM_DATA));
		break;
		
		case 0x4e:
		sprintf (buf, "lsr %s", find_symbol (ABS, SYM_DATA));
		break;
		
		case 0x5e:
		sprintf (buf, "lsr %s,X", find_symbol (ABS, SYM_DATA));
		break;
		
		case 0x6e:
		sprintf (buf, "ror %s", find_symbol (ABS, SYM_DATA));
		break;
		
		case 0x7e:
		sprintf (buf, "ror %s,X", find_symbol (ABS, SYM_DATA));
		break;
		
		case 0x8e:
		sprintf (buf, "stx %s", find_symbol (ABS, SYM_DATA));
		break;
		
#ifdef CMOS
		case 0x9e:
		sprintf (buf, "stz %s,X", find_symbol (ABS, SYM_DATA));
		break;
#endif
		
		case 0xae:
		sprintf (buf, "ldx %s", find_symbol (ABS, SYM_DATA));
		break;
		
		case 0xbe:
		sprintf (buf, "ldx %s,Y", find_symbol (ABS, SYM_DATA));
		break;
		
		case 0xce:
		sprintf (buf, "dec %s", find_symbol (ABS, SYM_DATA));
		break;
		
		case 0xde:
		sprintf (buf, "dec %s,X", find_symbol (ABS, SYM_DATA));
		break;
		
		case 0xee:
		sprintf (buf, "inc %s", find_symbol (ABS, SYM_DATA));
		break;
		
		case 0xfe:
		sprintf (buf, "inc %s,X", find_symbol (ABS, SYM_DATA));
		break;
		
		case 0x0f:
		case 0x1f:
		case 0x2f:
		case 0x3f:
		case 0x4f:
		case 0x5f:
		case 0x6f:
		case 0x7f:
		sprintf (buf, "bbr%d %s,%s", b & 0x07, hex (nextbyte ()),
			find_symbol (i = REL, SYM_CODE));
		//sync_points[n_syncpts++] = i;
		break;
		
		case 0x8f:
		case 0x9f:
		case 0xaf:
		case 0xbf:
		case 0xcf:
		case 0xdf:
		case 0xef:
		case 0xff:
		sprintf (buf, "bbs%d %s,%s", b & 0x07, hex (nextbyte ()),
			find_symbol (i = REL, SYM_CODE));
		//sync_points[n_syncpts++] = i;
		break;
		
		default:
		sprintf (buf, "db %s", hex (b));
		break;
	}
	return buf;
}

void do_disasm (int start, int l, char *buf)
{
	int oldptr = ptr = start-base_addr;
	struct symbol *sym;
	struct range *rng;
	int decode_type;
	int decode_end;
	int i, j, in_string;
	
	len = l;
	buffer = buf;
	
	while (ptr < len)
	{
		decode_type = 0;
		decode_end = 0;
		for (sym = first_sym; sym != NULL; sym = sym->next)
		{
			/*if (sym->type & SYM_CODE)
			{*/
				// Check if we need to re-sync
				if ((oldptr+base_addr) < sym->addr &&
					(ptr+base_addr) > sym->addr)
				{
					printf ("Sync @ %s (%x)\n", sym->name,
						sym->addr);
					ptr = sym->addr-base_addr;
				}
				if ((ptr+base_addr) == sym->addr)
					printf ("%s:\n", sym->name);
			//}
		}
		for (rng = first_rng; rng != NULL; rng = rng->next)
			if (rng->addr <= (ptr+base_addr) && rng->end >= (ptr+base_addr))
			{
				decode_type |= rng->type;
				decode_end = rng->end;
			}
		oldptr = ptr;
		if (decode_type & SYM_DATA)
		{
			printf ("%04X\t\tdb ", oldptr+base_addr);
			for (i = 0; decode_end >= (ptr+base_addr); i++)
			{
				if (i == 16)
				{
					printf ("\n\t\tdb ");
					i = 0;
				}
				printf ("%02x ", nextbyte ());
			}
			printf ("\n");
			continue;
		}
		if ((decode_type & SYM_CODE) || !decode_type)
			printf ("%04X\t\t%s\n", oldptr+base_addr,
				disasm_instruc ());
		if (decode_type & SYM_STRING)
		{
			printf ("%04X\t\tdb ", oldptr+base_addr);
			in_string = 0;
			j = 0;
			for (i = 0; decode_end >= (ptr+base_addr); i++)
			{
				if (i >= 50 && (j <= 32 || j >= 128))
				{
					if (in_string)
						printf ("\"\n\t\tdb ");
					else
						printf ("\n\t\tdb ");
					in_string = 0;
				}
				j = nextbyte ();
				if (j >= 32 && j <= 127)
				{
					if (!in_string)
					{
						printf ("\"%c", j);
						in_string = 1;
					}
					else
						printf ("%c", j);
				}
				else
				{
					if (in_string)
					{
						printf ("\" %02x ", j);
						in_string = 0;
					}
					else
						printf ("%02x ", j);
				}
			}
			if (in_string)
				printf ("\"\n");
			else
				printf ("\n");
			continue;
		}
	}
}

/* End of file. */
