aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--6502.c276
-rw-r--r--6502.h28
-rw-r--r--README.md6
3 files changed, 295 insertions, 15 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 */
diff --git a/6502.h b/6502.h
index 3b68ac5..735a6f6 100644
--- a/6502.h
+++ b/6502.h
@@ -84,33 +84,31 @@ typedef int (*C6502Callback)(C6502 *cpu, C6502Val current_cycles);
/* Callback reasons
- eC6502_Instruction Called before the initial fetch for an instruction
- (called just to once no matter how many bytes the
- instruction is made up of).
+ e6502_Instruction Called before the initial fetch for an instruction.
- eC6502_BRK Called when a BRK is executed.
+ e6502_BRK Called when a BRK is executed.
- eC6502_JAM Called when the CPU hits an opcode that jams the CPU.
+ e6502_JAM Called when the CPU hits an opcode that jams the CPU.
- eC6502_RTI Called when the RTI instruction is executed
+ e6502_RTI Called when the RTI instruction is executed
*/
typedef enum
{
- eC6502_Instruction,
- eC6502_BRK,
- eC6502_JAM,
- eC6502_RTI,
- eC6502_NO_CALLBACK
+ e6502_Instruction,
+ e6502_BRK,
+ e6502_JAM,
+ e6502_RTI,
+ e6502_NO_CALLBACK
} C6502CallbackReason;
/* Defines cycle timers
*/
typedef enum
{
- C6502_TIMER_1,
- C6502_TIMER_2,
- C6502_TIMER_3,
- C6502_NO_TIMERS
+ e6502_TIMER_1,
+ e6502_TIMER_2,
+ e6502_TIMER_3,
+ e6502_NO_TIMERS
} C6502Timer;
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..3809fc2
--- /dev/null
+++ b/README.md
@@ -0,0 +1,6 @@
+# 6502
+
+6502 is a simply library that can be incorporated by adding 6520.h and 6502.c
+into your project and building them as part of your sources. The code uses
+just ANSI/ISO features though it does check that types are as expected and
+calls exit() if they are not.