diff options
-rw-r--r-- | 6502.c | 276 | ||||
-rw-r--r-- | 6502.h | 28 | ||||
-rw-r--r-- | README.md | 6 |
3 files changed, 295 insertions, 15 deletions
@@ -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 */ @@ -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. |