aboutsummaryrefslogtreecommitdiff
path: root/6502.c
diff options
context:
space:
mode:
Diffstat (limited to '6502.c')
-rw-r--r--6502.c276
1 files changed, 276 insertions, 0 deletions
diff --git a/6502.c b/6502.c
new file mode 100644
index 0000000..0f9c954
--- /dev/null
+++ b/6502.c
@@ -0,0 +1,276 @@
+/*
+
+ 6502 - 6502 emulation
+
+ Copyright (C) 2025 Ian Cowburn <ianc@noddybox.co.uk>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>
+
+ -------------------------------------------------------------------------
+
+ 6502
+
+*/
+#include <stdlib.h>
+#include <string.h>
+
+#include "6502.h"
+
+
+/* ---------------------------------------- MACROS
+*/
+#define PRIV cpu->priv
+#define MAX_PER_CALLBACK 10
+#define TRUE 1
+#define FALSE 0
+
+#define CALLBACK(r,d) do \
+ { \
+ int f; \
+ \
+ for(f = 0; f < MAX_PER_CALLBACK; f++) \
+ if (PRIV->callback[r][f]) \
+ PRIV->last_cb &= \
+ PRIV->callback[r][f](cpu,d);\
+ } while(0)
+
+/* ---------------------------------------- PRIVATE DATA AND TYPES
+*/
+struct C6502Private
+{
+ C6502Val cycles;
+ C6502Val timer[e6502_NO_TIMERS];
+ C6502ReadMemory mread;
+ C6502WriteMemory mwrite;
+ C6502ReadMemory disread;
+ C6502Callback callback[e6502_NO_CALLBACK][MAX_PER_CALLBACK];
+ C6502Label *labels;
+ int last_cb;
+};
+
+/* ---------------------------------------- PRIVATE FUNCTIONS
+*/
+static void InitTables()
+{
+ static int init=FALSE;
+
+ if (init)
+ return;
+
+ init=TRUE;
+
+ /* TODO */
+}
+
+static void C6502_CheckInterrupt(C6502 *cpu)
+{
+ /* TODO */
+}
+
+
+/* ---------------------------------------- INTERFACES
+*/
+C6502 *C6502Init(C6502ReadMemory read_memory,
+ C6502WriteMemory write_memory,
+ C6502ReadMemory read_for_disassem)
+{
+ C6502 *cpu;
+ int f;
+ int r;
+
+ InitTables();
+
+ cpu = malloc(sizeof *cpu);
+
+ if (cpu)
+ {
+ PRIV = malloc(sizeof *cpu->priv);
+
+ if (PRIV)
+ {
+ PRIV->mread = read_memory;
+ PRIV->mwrite = write_memory;
+ PRIV->disread = read_for_disassem;
+
+ for(f = 0; f < eC6502_NO_CALLBACK; f++)
+ for(r = 0; r < MAX_PER_CALLBACK; r++)
+ PRIV->callback[f][r] = NULL;
+
+ C6502Reset(cpu);
+ }
+ else
+ {
+ free(cpu);
+ cpu = NULL;
+ }
+ }
+
+ return cpu;
+}
+
+
+void Z80Reset(Z80 *cpu)
+{
+ PRIV->cycle = 0;
+ PRIV->timer[e6502_TIMER_1] = 0;
+ PRIV->timer[e6502_TIMER_2] = 0;
+ PRIV->timer[e6502_TIMER_3] = 0;
+
+ cpu->PC = 0;
+
+ /* TODO */
+
+}
+
+
+C6502Val C6502Cycles(C6502 *cpu)
+{
+ return PRIV->cycle;
+}
+
+
+void C6502ResetCycles(C6502 *cpu, C6502Val cycles)
+{
+ PRIV->cycle = cycles;
+}
+
+
+C6502Val C6502GetTimer(C6502 *cpu, C6502Timer timer)
+{
+ return PRIV->timer[timer];
+}
+
+
+void C6502SetTimer(C6502 *cpu, C6502Timer timer, C6502Val cycles)
+{
+ PRIV->timer[timer] = cycles;
+}
+
+
+int C6502LodgeCallback(C6502 *cpu,
+ C6502CallbackReason reason,
+ C6502Callback callback)
+{
+ int f;
+
+ for(f = 0; f < MAX_PER_CALLBACK; f++)
+ {
+ if (!PRIV->callback[reason][f])
+ {
+ PRIV->callback[reason][f] = callback;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+
+void C6502RemoveCallback(C6502 *cpu,
+ C6502CallbackReason reason,
+ C6502Callback callback)
+{
+ int f;
+
+ for(f = 0; f < MAX_PER_CALLBACK; f++)
+ {
+ if (PRIV->callback[reason][f] == callback)
+ {
+ PRIV->callback[reason][f] = NULL;
+ }
+ }
+}
+
+
+void C6502Interrupt(C6502 *cpu)
+{
+ PRIV->raise = TRUE;
+ PRIV->nmi = FALSE;
+}
+
+
+void C6502NMI(C6502 *cpu)
+{
+ PRIV->raise = TRUE;
+ PRIV->nmi = TRUE;
+}
+
+
+int C6502SingleStep(C6502 *cpu)
+{
+ C6502_CheckInterrupt(cpu);
+
+ CALLBACK(eC6502_Instruction, PRIV->cycle);
+
+ INC_R;
+
+ opcode=FETCH_BYTE;
+
+ C6502_Decode(cpu,opcode);
+
+ return PRIV->last_cb;
+}
+
+
+void C6502Exec(C6502 *cpu)
+{
+ while (C6502SingleStep(cpu));
+}
+
+
+void C6502SetLabels(C6502 *cpu, C6502Label labels[])
+{
+ PRIV->labels = labels;
+}
+
+
+const char *C6502Disassemble(C6502 *cpu, C6502Word *pc)
+{
+#ifdef ENABLE_DISASSEM
+ C6502Byte C6502_Dis_FetchByte(C6502 *cpu, C6502Word *pc);
+ static char s[80];
+ C6502Word opc,npc;
+ C6502Byte op;
+ int f;
+
+ opc=*pc;
+ op=C6502_Dis_FetchByte(cpu,pc);
+ dis_opcode_z80[op](cpu,op,pc);
+ npc=*pc;
+
+ strcpy(s,C6502_Dis_Printf("%-5s",C6502_Dis_GetOp()));
+ strcat(s,C6502_Dis_Printf("%-40s ;",C6502_Dis_GetArg()));
+
+ for(f=0;f<5 && opc!=npc;f++)
+ {
+#ifdef ENABLE_ARRAY_MEMORY
+ strcat(s,C6502_Dis_Printf(" %.2x",(int)C6502_MEMORY[opc++]));
+#else
+ strcat(s,C6502_Dis_Printf(" %.2x",(int)PRIV->disread(cpu,opc++)));
+#endif
+ }
+
+ if (opc!=npc)
+ for(f=1;f<3;f++)
+ s[strlen(s)-f]='.';
+
+ return s;
+#else
+ (*pc)+=4;
+ return "NO DISASSEMBLER";
+#endif
+}
+
+
+/* END OF FILE */