~swisschili/toolchain-6502

1970cb8118b3cdb79f715bb3e9173acd8dee9786 — swissChili 3 months ago c6b4f7e
Multithread gui, remove hard coded cpu->pc
8 files changed, 85 insertions(+), 91 deletions(-)

A a.out
M colors.dat
M cpu.c
M cpu.h
M dbg.c
A disco.dat
M gui.c
M screen.c
A a.out => a.out +0 -0

M colors.dat => colors.dat +0 -0

M cpu.c => cpu.c +49 -63
@@ 146,14 146,6 @@ void cmp(cpu_t *cpu, uint8_t reg, uint8_t mem)
	}
}

uint16_t scr_dirty(cpu_t *cpu, uint16_t mem)
{
	if (mem >= 0x200 && mem <= 0x200 + 32 * 32)
		cpu->screen_dirty = true;

	return mem;
}

void execute(cpu_t *cpu, const char *mnemonic, uint8_t op, arg_t a, uint8_t am)
{
	// used to save space


@@ 174,7 166,7 @@ void execute(cpu_t *cpu, const char *mnemonic, uint8_t op, arg_t a, uint8_t am)

		#define R(reg) \
			case ST##reg: \
				cpu->mem[scr_dirty(cpu, a.ptr)] = cpu->regs[reg]; \
				cpu->mem[a.ptr] = cpu->regs[reg]; \
				break; \

			REGS


@@ 204,8 196,8 @@ void execute(cpu_t *cpu, const char *mnemonic, uint8_t op, arg_t a, uint8_t am)
		}

		case INC:
			cpu->mem[scr_dirty(cpu, scr_dirty(cpu, a.ptr))]++;
			stat_nz(cpu, cpu->mem[scr_dirty(cpu, a.ptr)]);
			cpu->mem[a.ptr]++;
			stat_nz(cpu, cpu->mem[a.ptr]);
			break;

		case INX:


@@ 219,8 211,8 @@ void execute(cpu_t *cpu, const char *mnemonic, uint8_t op, arg_t a, uint8_t am)
			break;

		case DEC:
			cpu->mem[scr_dirty(cpu, a.ptr)]--;
			stat_nz(cpu, cpu->mem[scr_dirty(cpu, a.ptr)]);
			cpu->mem[a.ptr]--;
			stat_nz(cpu, cpu->mem[a.ptr]);
			break;

		case DEX:


@@ 245,9 237,9 @@ void execute(cpu_t *cpu, const char *mnemonic, uint8_t op, arg_t a, uint8_t am)
			}
			else
			{
				cpu->status.carry = cpu->mem[scr_dirty(cpu, a.val)] >> 7;
				cpu->mem[scr_dirty(cpu, a.ptr)] <<= 1;
				stat_nz(cpu, cpu->mem[scr_dirty(cpu, a.ptr)]);
				cpu->status.carry = cpu->mem[a.val] >> 7;
				cpu->mem[a.ptr] <<= 1;
				stat_nz(cpu, cpu->mem[a.ptr]);
			}
			break;



@@ 260,9 252,9 @@ void execute(cpu_t *cpu, const char *mnemonic, uint8_t op, arg_t a, uint8_t am)
			}
			else
			{
				cpu->status.carry = cpu->mem[scr_dirty(cpu, a.val)] & 7;
				cpu->mem[scr_dirty(cpu, a.ptr)] >>= 1;
				stat_nz(cpu, cpu->mem[scr_dirty(cpu, a.ptr)]);
				cpu->status.carry = cpu->mem[a.val] & 7;
				cpu->mem[a.ptr] >>= 1;
				stat_nz(cpu, cpu->mem[a.ptr]);
			}
			break;



@@ 275,9 267,9 @@ void execute(cpu_t *cpu, const char *mnemonic, uint8_t op, arg_t a, uint8_t am)
			}
			else
			{
				cpu->status.carry = cpu->mem[scr_dirty(cpu, a.val)] >> 7;
				cpu->mem[scr_dirty(cpu, a.ptr)] = rol(a.val, 1);
				stat_nz(cpu, cpu->mem[scr_dirty(cpu, a.ptr)]);
				cpu->status.carry = cpu->mem[a.val] >> 7;
				cpu->mem[a.ptr] = rol(a.val, 1);
				stat_nz(cpu, cpu->mem[a.ptr]);
			}
			break;



@@ 290,9 282,9 @@ void execute(cpu_t *cpu, const char *mnemonic, uint8_t op, arg_t a, uint8_t am)
			}
			else
			{
				cpu->status.carry = cpu->mem[scr_dirty(cpu, a.val)] & 1;
				cpu->mem[scr_dirty(cpu, a.ptr)] = ror(a.val, 1);
				stat_nz(cpu, cpu->mem[scr_dirty(cpu, a.ptr)]);
				cpu->status.carry = cpu->mem[a.val] & 1;
				cpu->mem[a.ptr] = ror(a.val, 1);
				stat_nz(cpu, cpu->mem[a.ptr]);
			}
			break;



@@ 423,10 415,10 @@ void execute(cpu_t *cpu, const char *mnemonic, uint8_t op, arg_t a, uint8_t am)
	#undef REGS
}

uint16_t fetch_le(cpu_t *cpu)
uint16_t fetch_le(cpu_t *cpu, uint16_t *pc)
{
	uint8_t a = cpu->mem[scr_dirty(cpu, cpu->pc++)];
	uint8_t b = cpu->mem[scr_dirty(cpu, cpu->pc++)];
	uint8_t a = cpu->mem[(*pc)++];
	uint8_t b = cpu->mem[(*pc)++];
	return le_to_native(a, b);
}



@@ 448,7 440,7 @@ arg_t arg(uint16_t v, uint16_t a)
	return (arg_t){ v, a };
}

arg_t fetch_addr(cpu_t *cpu, uint8_t am, uint f)
arg_t fetch_addr(cpu_t *cpu, uint8_t am, uint f, uint16_t *pc)
{
	switch (am)
	{


@@ 459,59 451,55 @@ arg_t fetch_addr(cpu_t *cpu, uint8_t am, uint f)
		// In both cases return immediate 8 bit value
		case AM_IMM:
		case AM_ZP:
			return arg_imm(cpu->mem[scr_dirty(cpu, cpu->pc++)]);
			return arg_imm(cpu->mem[(*pc)++]);

		case AM_ABS:
			return arg_ptr(cpu, f, fetch_le(cpu));
			return arg_ptr(cpu, f, fetch_le(cpu, pc));

		case AM_REL:
		{
			// Aparently, PC should will point to the NEXT opcode
			// I can't find any documentation on this unfortunately, but
			// I have discovered this through testing the output of other
			// assemblers.
			uint16_t pc = cpu->pc + 1;
			return arg_ptr(cpu, f, (int8_t)cpu->mem[scr_dirty(cpu, cpu->pc++)] + pc);
			uint16_t pc_hi = * pc + 1;
			return arg_ptr(cpu, f, (int8_t)cpu->mem[(*pc)++] + pc_hi);
		}

		case AM_IND:
		{
			uint16_t addr = fetch_le(cpu);
			uint16_t addr = fetch_le(cpu, pc);

			if (f & FETCH_NO_INDIRECTION)
				return arg_imm(addr);

			uint8_t low = cpu->mem[scr_dirty(cpu, addr)],
				high = cpu->mem[scr_dirty(cpu, addr + 1)];
			uint8_t low = cpu->mem[addr],
				high = cpu->mem[addr + 1];

			return arg_ptr(cpu, f, le_to_native(low, high));
		}

		case AM_AX:
			if (f & FETCH_NO_INDIRECTION)
				return arg_ptr(cpu, f, fetch_le(cpu));
				return arg_ptr(cpu, f, fetch_le(cpu, pc));

			return arg_ptr(cpu, f, fetch_le(cpu) + cpu->regs[X]);
			return arg_ptr(cpu, f, fetch_le(cpu, pc) + cpu->regs[X]);

		case AM_AY:
			if (f & FETCH_NO_INDIRECTION)
				return arg_ptr(cpu, f, fetch_le(cpu));
				return arg_ptr(cpu, f, fetch_le(cpu, pc));
		
			return arg_ptr(cpu, f, fetch_le(cpu) + cpu->regs[Y]);
			return arg_ptr(cpu, f, fetch_le(cpu, pc) + cpu->regs[Y]);

		case AM_ZPX:
			if (f & FETCH_NO_INDIRECTION)
				return arg_ptr(cpu, f, cpu->mem[cpu->pc++]);
			return arg_ptr(cpu, f, cpu->mem[cpu->pc++] + cpu->regs[X]);
				return arg_ptr(cpu, f, cpu->mem[(*pc)++]);
			return arg_ptr(cpu, f, cpu->mem[(*pc)++] + cpu->regs[X]);

		case AM_ZPY:
			if (f & FETCH_NO_INDIRECTION)
				return arg_ptr(cpu, f, cpu->mem[cpu->pc++]);
			return arg_ptr(cpu, f, cpu->mem[cpu->pc++] + cpu->regs[Y]);
				return arg_ptr(cpu, f, cpu->mem[(*pc)++]);
			return arg_ptr(cpu, f, cpu->mem[(*pc)++] + cpu->regs[Y]);

		case AM_ZIX:
		{
			uint8_t zp = cpu->mem[cpu->pc++];
			uint8_t zp = cpu->mem[(*pc)++];

			if (f & FETCH_NO_INDIRECTION)
				return arg_imm(zp);


@@ 523,12 511,12 @@ arg_t fetch_addr(cpu_t *cpu, uint8_t am, uint f)

		case AM_ZIY:
		{
			uint8_t zp = cpu->mem[scr_dirty(cpu, cpu->pc++)];
			uint8_t zp = cpu->mem[(*pc)++];

			if (f & FETCH_NO_INDIRECTION)
				return arg_imm(zp);

			uint16_t base = le_to_native(cpu->mem[zp], cpu->mem[scr_dirty(cpu, zp + 1)]);
			uint16_t base = le_to_native(cpu->mem[zp], cpu->mem[zp + 1]);
			return arg_ptr(cpu, f, base + cpu->regs[Y]);
		}



@@ 548,7 536,7 @@ void step(cpu_t *cpu)
	{
#define INST(mn, am, op) \
		case op: \
			execute(cpu, #mn, mn, fetch_addr(cpu, am, 0), am); \
			execute(cpu, #mn, mn, fetch_addr(cpu, am, 0, &cpu->pc), am); \
			break;

		INSTRUCTIONS


@@ 602,19 590,19 @@ int dump_inst(cpu_t *cpu, char *buf, const char *mn, uint16_t addr, uint8_t am)
	return end - buf;
}

char *disas_step(cpu_t *cpu)
char *disas_step(cpu_t *cpu, uint16_t *pc)
{
	char *buffer = malloc(80);
	char *end = buffer;

	// end += sprintf(buffer, "$%x", cpu->pc);
	uint8_t op = cpu->mem[scr_dirty(cpu, cpu->pc++)];
	uint8_t op = cpu->mem[(*pc)++];
	switch (op)
	{
#define INST(mn, am, op) \
		case op: \
			end += dump_inst(cpu, end, #mn, \
				fetch_addr(cpu, am, FETCH_NO_INDIRECTION).ptr, am); \
				fetch_addr(cpu, am, FETCH_NO_INDIRECTION, pc).ptr, am); \
			break;

		INSTRUCTIONS


@@ 632,29 620,27 @@ char *disas_step(cpu_t *cpu)

void disas_num(cpu_t *cpu, uint16_t num)
{
	uint16_t pc = cpu->pc;
	uint16_t pc = 0x600;
	for (int i = 0; i < num; i++)
	{
		uint16_t last_pc = cpu->pc;
		char *line = disas_step(cpu);
		uint16_t last_pc = pc;
		char *line = disas_step(cpu, &pc);
		printf("$%x\t%s\n", last_pc, line);
		free(line);
	}
	cpu->pc = pc;
}

void disas(cpu_t *cpu)
{
	uint16_t pc = cpu->pc;
	uint16_t pc = 0x600;
	// Raw binary, no way to know what's code what isn't
	while (cpu->pc < 0xFFFF)
	{
		uint16_t last_pc = cpu->pc;
		char *line = disas_step(cpu);
		uint16_t last_pc = pc;
		char *line = disas_step(cpu, &pc);
		printf("$%x\t%s\n", last_pc, line);
		free(line);
	}
	cpu->pc = pc;
}

void run(cpu_t *cpu)

M cpu.h => cpu.h +1 -1
@@ 150,6 150,6 @@ void reset(cpu_t *cpu);
void disas(cpu_t *cpu);
void disas_num(cpu_t *cpu, uint16_t num);
// Buffer must be freed by user
char *disas_step(cpu_t *cpu);
char *disas_step(cpu_t *cpu, uint16_t *pc);
void run(cpu_t *cpu);
void run_mq(cpu_t *cpu, mqd_t mq);

M dbg.c => dbg.c +4 -0
@@ 52,6 52,10 @@ bool debug_stmt(cpu_t *cpu, char *input, bool *running)
	{
		*running = true;
	}
	else if (!strcmp(tok, "pause"))
	{
		*running = false;
	}
	else if (!strcmp(tok, "quit") || !strcmp(tok, "exit"))
	{
		printf("Bye\n");

A disco.dat => disco.dat +0 -0

M gui.c => gui.c +23 -21
@@ 1,4 1,5 @@
#include "gui.h"
#include "common.h"

#include <GL/glew.h>
#include <SDL2/SDL.h>


@@ 29,6 30,11 @@ typedef struct
	mqd_t mq;
} gui_arg_t;

static void cmd(mqd_t mq, char *msg)
{
	mq_send(mq, msg, strlen(msg) + 1, 2);
}

void gui(gui_arg_t *arg)
{
	cpu_t *cpu = arg->cpu;


@@ 76,8 82,7 @@ void gui(gui_arg_t *arg)
	glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
	glewExperimental = 1;
	if (glewInit() != GLEW_OK) {
		fprintf(stderr, "Failed to setup GLEW\n");
		exit(1);
		THROW("Failed to setup GLEW\n");
	}

	ctx = nk_sdl_init(win);


@@ 100,9 105,6 @@ void gui(gui_arg_t *arg)
		}
		nk_input_end(ctx);

		if (cpu_running && cpu->running)
			step(cpu);

		if (!cpu->running)
			cpu_running = false;



@@ 111,10 113,10 @@ void gui(gui_arg_t *arg)
			NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))
		{
			nk_layout_row_dynamic(ctx, 30, 4);
			cpu->pc = nk_propertyi(ctx, "PC", 0, cpu->pc, 0xFFFF, 1, 20.0f);
			cpu->regs[A] = nk_propertyi(ctx, "A", 0, cpu->regs[A], 0xFF, 1, 20.0f);
			cpu->regs[X] = nk_propertyi(ctx, "X", 0, cpu->regs[X], 0xFF, 1, 20.0f);
			cpu->regs[Y] = nk_propertyi(ctx, "Y", 0, cpu->regs[Y], 0xFF, 1, 20.0f);
			uint16_t pc = nk_propertyi(ctx, "PC", 0, cpu->pc, 0xFFFF, 1, 20.0f);
			uint8_t rega = nk_propertyi(ctx, "A", 0, cpu->regs[A], 0xFF, 1, 20.0f),
				regx = nk_propertyi(ctx, "X", 0, cpu->regs[X], 0xFF, 1, 20.0f),
				regy = nk_propertyi(ctx, "Y", 0, cpu->regs[Y], 0xFF, 1, 20.0f);
		}
		nk_end(ctx);



@@ 123,7 125,7 @@ void gui(gui_arg_t *arg)
			NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))
		{
			nk_layout_row_dynamic(ctx, 24, 1);
			screen_scale = nk_propertyi(ctx, "Scale", 1, screen_scale, 8, 1, 1);
			screen_scale = nk_propertyi(ctx, "Scale", 1, screen_scale, 16, 1, 1);

			nk_layout_row_static(ctx, screen_scale * 32, screen_scale * 32, 1);
			screen(ctx, cpu->mem + CPU_FB_ADDR, screen_scale);


@@ 138,23 140,22 @@ void gui(gui_arg_t *arg)
			disas_start = nk_propertyi(ctx, "Start", 0, disas_start, 0xFFFF, 1, 20.0f);
			disas_end = nk_propertyi(ctx, "End", 0, disas_end, 0xFFFF, 1, 20.0f);

			uint16_t pc = cpu->pc;

			for (cpu->pc = disas_start; cpu->pc < disas_end;)
			for (uint16_t pc = disas_start; pc < disas_end;)
			{
				nk_layout_row_begin(ctx, NK_STATIC, 24, 2);

				uint16_t this_pc = cpu->pc;
				uint16_t cpu_pc = cpu->pc,
					this_pc = pc;
			
				char addr[6];
				sprintf(addr, "$%x", this_pc);
				sprintf(addr, "$%x", pc);

				nk_layout_row_push(ctx, 48);
				nk_label(ctx, addr, NK_TEXT_LEFT);

				nk_layout_row_push(ctx, 120);
				char *line = disas_step(cpu);
				if (pc == this_pc)
				char *line = disas_step(cpu, &pc);
				if (cpu_pc == this_pc)
				{
					nk_label_colored(ctx, line, NK_TEXT_LEFT, selected);
				}


@@ 164,8 165,6 @@ void gui(gui_arg_t *arg)
				}
				free(line);
			}

			cpu->pc = pc;
		}
		nk_end(ctx);



@@ 202,18 201,19 @@ void gui(gui_arg_t *arg)
			if (nk_button_label(ctx, "Reset"))
			{
				puts("cpu reset");
				reset(cpu);
				cmd(mq, "reset");
			}

			nk_layout_row_dynamic(ctx, 30, 2);
			if (nk_button_label(ctx, "Step"))
			{
				printf("step pressed!\n");
				step(cpu);
				cmd(mq, "step");
			}

			if (nk_button_label(ctx, cpu_running ? "Stop" : "Run"))
			{
				cmd(mq, cpu_running ? "pause" : "run");
				cpu_running = !cpu_running;
				puts(cpu_running ? "cpu running" : "cpu stopped");
			}


@@ 233,6 233,8 @@ cleanup:
	SDL_GL_DeleteContext(glContext);
	SDL_DestroyWindow(win);
	SDL_Quit();

	cmd(mq, "quit");
}



M screen.c => screen.c +8 -6
@@ 26,18 26,20 @@ void screen(struct nk_context *ctx, uint8_t *mem, uint8_t size)
	if (!state)
		return;

	//nk_fill_rect(out, bounds, 0, nk_rgb(255, 0, 0));
	nk_fill_rect(out, bounds, 0, nk_rgb(0, 0, 0));

	//return;

	for (int i = 0; i < CPU_FB_H; i++)
	{
		for (int j = 0; j < CPU_FB_W; j++)
		{
			nk_fill_rect(out,
				nk_rect(bounds.x + i * size, bounds.y + j * size,
					size, size), 0.0f,
				byte_to_color(mem[i + CPU_FB_H * j]));
			if (mem[i + CPU_FB_H * j])
			{
				nk_fill_rect(out,
					nk_rect(bounds.x + i * size, bounds.y + j * size,
						size, size), 0.0f,
					byte_to_color(mem[i + CPU_FB_H * j]));
			}
		}
	}
}