From 1e6085c4580bd1a4b468ed58c34155b188dafdbd Mon Sep 17 00:00:00 2001 From: Dario48 Date: Mon, 18 Aug 2025 21:14:29 +0200 Subject: [PATCH] init --- .gitignore | 3 + build.zig | 122 ++++ build.zig.zon | 86 +++ src/main.zig | 64 +++ src/root.zig | 1484 +++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 1759 insertions(+) create mode 100644 .gitignore create mode 100644 build.zig create mode 100644 build.zig.zon create mode 100644 src/main.zig create mode 100644 src/root.zig diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1c22b48 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.zig-cache +zig-out +.DS_Store diff --git a/build.zig b/build.zig new file mode 100644 index 0000000..5652a6f --- /dev/null +++ b/build.zig @@ -0,0 +1,122 @@ +const std = @import("std"); + +// Although this function looks imperative, note that its job is to +// declaratively construct a build graph that will be executed by an external +// runner. +pub fn build(b: *std.Build) void { + // Standard target options allows the person running `zig build` to choose + // what target to build for. Here we do not override the defaults, which + // means any target is allowed, and the default is native. Other options + // for restricting supported target set are available. + const target = b.standardTargetOptions(.{}); + + // Standard optimization options allow the person running `zig build` to select + // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not + // set a preferred release mode, allowing the user to decide how to optimize. + const optimize = b.standardOptimizeOption(.{}); + + // options + const options = b.addOptions(); + options.addOption(bool, "CMOS_INDIRECT_JMP_FIX", false); + + // This creates a "module", which represents a collection of source files alongside + // some compilation options, such as optimization mode and linked system libraries. + // Every executable or library we compile will be based on one or more modules. + const lib_mod = b.createModule(.{ + // `root_source_file` is the Zig "entry point" of the module. If a module + // only contains e.g. external object files, you can make this `null`. + // In this case the main source file is merely a path, however, in more + // complicated build scripts, this could be a generated file. + .root_source_file = b.path("src/root.zig"), + .target = target, + .optimize = optimize, + }); + + lib_mod.addOptions("config", options); + + // We will also create a module for our other entry point, 'main.zig'. + const exe_mod = b.createModule(.{ + // `root_source_file` is the Zig "entry point" of the module. If a module + // only contains e.g. external object files, you can make this `null`. + // In this case the main source file is merely a path, however, in more + // complicated build scripts, this could be a generated file. + .root_source_file = b.path("src/main.zig"), + .target = target, + .optimize = optimize, + }); + + // Modules can depend on one another using the `std.Build.Module.addImport` function. + // This is what allows Zig source code to use `@import("foo")` where 'foo' is not a + // file path. In this case, we set up `exe_mod` to import `lib_mod`. + exe_mod.addImport("mos6502lib", lib_mod); + + // Now, we will create a static library based on the module we created above. + // This creates a `std.Build.Step.Compile`, which is the build step responsible + // for actually invoking the compiler. + const lib = b.addLibrary(.{ + .linkage = .static, + .name = "mos6502lib", + .root_module = lib_mod, + }); + + // This declares intent for the library to be installed into the standard + // location when the user invokes the "install" step (the default step when + // running `zig build`). + b.installArtifact(lib); + + // This creates another `std.Build.Step.Compile`, but this one builds an executable + // rather than a static library. + const exe = b.addExecutable(.{ + .name = "mos6502", + .root_module = exe_mod, + }); + + // This declares intent for the executable to be installed into the + // standard location when the user invokes the "install" step (the default + // step when running `zig build`). + b.installArtifact(exe); + + // This *creates* a Run step in the build graph, to be executed when another + // step is evaluated that depends on it. The next line below will establish + // such a dependency. + const run_cmd = b.addRunArtifact(exe); + + // By making the run step depend on the install step, it will be run from the + // installation directory rather than directly from within the cache directory. + // This is not necessary, however, if the application depends on other installed + // files, this ensures they will be present and in the expected location. + run_cmd.step.dependOn(b.getInstallStep()); + + // This allows the user to pass arguments to the application in the build + // command itself, like this: `zig build run -- arg1 arg2 etc` + if (b.args) |args| { + run_cmd.addArgs(args); + } + + // This creates a build step. It will be visible in the `zig build --help` menu, + // and can be selected like this: `zig build run` + // This will evaluate the `run` step rather than the default, which is "install". + const run_step = b.step("run", "Run the app"); + run_step.dependOn(&run_cmd.step); + + // Creates a step for unit testing. This only builds the test executable + // but does not run it. + const lib_unit_tests = b.addTest(.{ + .root_module = lib_mod, + }); + + const run_lib_unit_tests = b.addRunArtifact(lib_unit_tests); + + const exe_unit_tests = b.addTest(.{ + .root_module = exe_mod, + }); + + const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests); + + // Similar to creating the run step earlier, this exposes a `test` step to + // the `zig build --help` menu, providing a way for the user to request + // running the unit tests. + const test_step = b.step("test", "Run unit tests"); + test_step.dependOn(&run_lib_unit_tests.step); + test_step.dependOn(&run_exe_unit_tests.step); +} diff --git a/build.zig.zon b/build.zig.zon new file mode 100644 index 0000000..f7af976 --- /dev/null +++ b/build.zig.zon @@ -0,0 +1,86 @@ +.{ + // This is the default name used by packages depending on this one. For + // example, when a user runs `zig fetch --save `, this field is used + // as the key in the `dependencies` table. Although the user can choose a + // different name, most users will stick with this provided value. + // + // It is redundant to include "zig" in this name because it is already + // within the Zig package namespace. + .name = .mos6502, + + // This is a [Semantic Version](https://semver.org/). + // In a future version of Zig it will be used for package deduplication. + .version = "0.0.0", + + // Together with name, this represents a globally unique package + // identifier. This field is generated by the Zig toolchain when the + // package is first created, and then *never changes*. This allows + // unambiguous detection of one package being an updated version of + // another. + // + // When forking a Zig project, this id should be regenerated (delete the + // field and run `zig build`) if the upstream project is still maintained. + // Otherwise, the fork is *hostile*, attempting to take control over the + // original project's identity. Thus it is recommended to leave the comment + // on the following line intact, so that it shows up in code reviews that + // modify the field. + .fingerprint = 0xd0ac32be7769a55b, // Changing this has security and trust implications. + + // Tracks the earliest Zig version that the package considers to be a + // supported use case. + .minimum_zig_version = "0.14.1", + + // This field is optional. + // Each dependency must either provide a `url` and `hash`, or a `path`. + // `zig build --fetch` can be used to fetch all dependencies of a package, recursively. + // Once all dependencies are fetched, `zig build` no longer requires + // internet connectivity. + .dependencies = .{ + // See `zig fetch --save ` for a command-line interface for adding dependencies. + //.example = .{ + // // When updating this field to a new URL, be sure to delete the corresponding + // // `hash`, otherwise you are communicating that you expect to find the old hash at + // // the new URL. If the contents of a URL change this will result in a hash mismatch + // // which will prevent zig from using it. + // .url = "https://example.com/foo.tar.gz", + // + // // This is computed from the file contents of the directory of files that is + // // obtained after fetching `url` and applying the inclusion rules given by + // // `paths`. + // // + // // This field is the source of truth; packages do not come from a `url`; they + // // come from a `hash`. `url` is just one of many possible mirrors for how to + // // obtain a package matching this `hash`. + // // + // // Uses the [multihash](https://multiformats.io/multihash/) format. + // .hash = "...", + // + // // When this is provided, the package is found in a directory relative to the + // // build root. In this case the package's hash is irrelevant and therefore not + // // computed. This field and `url` are mutually exclusive. + // .path = "foo", + // + // // When this is set to `true`, a package is declared to be lazily + // // fetched. This makes the dependency only get fetched if it is + // // actually used. + // .lazy = false, + //}, + }, + + // Specifies the set of files and directories that are included in this package. + // Only files and directories listed here are included in the `hash` that + // is computed for this package. Only files listed here will remain on disk + // when using the zig package manager. As a rule of thumb, one should list + // files required for compilation plus any license(s). + // Paths are relative to the build root. Use the empty string (`""`) to refer to + // the build root itself. + // A directory listed here means that all files within, recursively, are included. + .paths = .{ + "build.zig", + "build.zig.zon", + "src", + // For example... + //"LICENSE", + //"README.md", + }, +} diff --git a/src/main.zig b/src/main.zig new file mode 100644 index 0000000..cab55af --- /dev/null +++ b/src/main.zig @@ -0,0 +1,64 @@ +var mem: [0xFFFF]u8 = std.mem.zeroes([0xFFFF]u8); + +const err = error{WrongSyntax}; + +fn Read(where: u16) u8 { + return mem[where]; +} + +fn Write(where: u16, what: u8) void { + mem[where] = what; +} + +const functions = lib.Functions{ + .BusRead = Read, + .BusWrite = Write, + .ClockCycle = null, +}; + +pub fn main() !void { + var args = try std.process.argsWithAllocator(std.heap.smp_allocator); + + const programname = args.next().?; + + var file: std.fs.File = undefined; + + if (args.next()) |arg| { + file = std.fs.cwd().openFileZ(arg.ptr, .{}) catch |fileErr| switch (fileErr) { + error.FileNotFound => { + std.log.err("Please pass an existing file", .{}); + return fileErr; + }, + else => return fileErr, + }; + } else { + std.log.err("syntax: {s} file_to_run", .{programname}); + return error.WrongSyntax; + } + + args.deinit(); + + var fbs = std.io.fixedBufferStream(&mem); + + try fbs.seekTo(0x200); + + while (file.reader().readByte()) |byte| { + fbs.writer().writeByte(byte) catch |writeErr| { + std.log.err("file should be {} bytes at most", .{0xFFFF - 0x200}); + return writeErr; + }; + } else |readErr| { + switch (readErr) { + error.EndOfStream => {}, + else => return readErr, + } + } + + var mos6502 = lib.init(functions); + mos6502.pc = 0x1FF; + mos6502.RunEternally(); +} + +const std = @import("std"); + +const lib = @import("mos6502lib"); diff --git a/src/root.zig b/src/root.zig new file mode 100644 index 0000000..451e6b4 --- /dev/null +++ b/src/root.zig @@ -0,0 +1,1484 @@ +//!mos6502 emulator written in zig +//!based on https://github.com/gianlucag/mos6502/ + +const std = @import("std"); + +const mos6502 = @This(); + +const AddrExec = *const fn (self: *mos6502) u16; +const CodeExec = *const fn (self: *mos6502, u16) void; + +const Instr = struct { + addr: AddrExec, + code: CodeExec, + cycles: u8, +}; + +pub const Functions = struct { + BusRead: *const fn (u16) u8, + BusWrite: *const fn (u16, u8) void, + ClockCycle: ?*const fn (*mos6502) void, +}; + +// IRQ, reset, NMI vectors +const irqVectorH: u16 = 0xFFFF; +const irqVectorL: u16 = 0xFFFE; +const rstVectorH: u16 = 0xFFFD; +const rstVectorL: u16 = 0xFFFC; +const nmiVectorH: u16 = 0xFFFB; +const nmiVectorL: u16 = 0xFFFA; + +pub const CycleMethod = enum { + INST_COUNT, + CYCLE_COUNT, +}; + +// register reset values +reset_A: u8, +reset_X: u8, +reset_Y: u8, +reset_sp: u8, +reset_status: u8, + +// registers +A: u8, // accumulator +X: u8, // X-index +Y: u8, // Y-index + +// stack pointer +sp: u8, + +// program counter +pc: u16, + +// status register +status: u8, + +InstrTable: [256]Instr, + +illegalOpcode: bool, + +Read: *const fn (u16) u8, +Write: *const fn (u16, u8) void, +Cycle: ?*const fn (*mos6502) void, + +const NEGATIVE: u8 = 0x80; +const OVERFLOW: u8 = 0x40; +const CONSTANT: u8 = 0x20; +const BREAK: u8 = 0x10; +const DECIMAL: u8 = 0x08; +const INTERRUPT: u8 = 0x04; +const ZERO: u8 = 0x02; +const CARRY: u8 = 0x01; + +inline fn SET(self: *mos6502, x: anytype, what: u8) void { + if (@TypeOf(x) == u8 or @TypeOf(x) == u16) { + if (x != 0) { + self.status |= what; + return; + } + self.status &= (~what); + } else if (@TypeOf(x) == bool) { + if (x) { + self.status |= what; + return; + } + self.status &= what; + } +} + +inline fn SET_NEGATIVE(self: *mos6502, x: anytype) void { + self.SET(x, NEGATIVE); +} +inline fn SET_OVERFLOW(self: *mos6502, x: anytype) void { + self.SET(x, OVERFLOW); +} +inline fn SET_DECIMAL(self: *mos6502, x: anytype) void { + self.SET(x, DECIMAL); +} +inline fn SET_INTERRUPT(self: *mos6502, x: anytype) void { + self.SET(x, INTERRUPT); +} +inline fn SET_ZERO(self: *mos6502, x: anytype) void { + self.SET(x, ZERO); +} +inline fn SET_CARRY(self: *mos6502, x: anytype) void { + self.SET(x, CARRY); +} +fn IF_NEGATIVE(self: mos6502) bool { + return (self.status & NEGATIVE != 0); +} +fn IF_OVERFLOW(self: mos6502) bool { + return (self.status & OVERFLOW != 0); +} +fn IF_CONSTANT(self: mos6502) bool { + return (self.status & CONSTANT != 0); +} +fn IF_BREAK(self: mos6502) bool { + return (self.status & BREAK != 0); +} +fn IF_DECIMAL(self: mos6502) bool { + return (self.status & DECIMAL != 0); +} +fn IF_INTERRUPT(self: mos6502) bool { + return (self.status & INTERRUPT != 0); +} +fn IF_ZERO(self: mos6502) bool { + return (self.status & ZERO != 0); +} +fn IF_CARRY(self: mos6502) bool { + return (self.status & CARRY != 0); +} + +fn Addr_ACC(_: *mos6502) u16 { + return 0; // not used +} + +fn Addr_IMM(self: *mos6502) u16 { + self.pc +%= 1; + return self.pc; +} + +fn Addr_ABS(self: *mos6502) u16 { + var addrL: u16 = undefined; + var addrH: u16 = undefined; + var addr: u16 = undefined; + + self.pc +%= 1; + addrL = self.Read(self.pc); + self.pc +%= 1; + addrH = self.Read(self.pc); + + addr = addrL +% (addrH << 8); + + return addr; +} + +fn Addr_ZER(self: *mos6502) u16 { + self.pc +%= 1; + return self.Read(self.pc); +} + +fn Addr_IMP(_: *mos6502) u16 { + return 0; // not used +} + +fn Addr_REL(self: *mos6502) u16 { + var offset: u16 = undefined; + var addr: u16 = undefined; + + self.pc +%= 1; + offset = self.Read(self.pc); + if (offset & 0x80 != 0) offset |= 0xFF00; + addr = self.pc +% offset; + return addr; +} + +fn Addr_ABI(self: *mos6502) u16 { + var addrL: u16 = undefined; + var addrH: u16 = undefined; + var effL: u16 = undefined; + var effH: u16 = undefined; + var abs: u16 = undefined; + var addr: u16 = undefined; + + self.pc +%= 1; + addrL = self.Read(self.pc); + self.pc +%= 1; + addrH = self.Read(self.pc); + + abs = (addrH << 8) | addrL; + + effL = self.Read(abs); + + if (@import("config").CMOS_INDIRECT_JMP_FIX) + effH = self.Read((abs & 0xFF00) +% ((abs + 1) & 0x00FF)) + else + effH = self.Read(abs +% 1); + + addr = effL +% 0x100 * effH; + + return addr; +} + +fn Addr_ZEX(self: *mos6502) u16 { + self.pc +%= 1; + return (self.Read(self.pc) +% self.X) & 0xFF; +} + +fn Addr_ZEY(self: *mos6502) u16 { + self.pc +%= 1; + return (self.Read(self.pc) +% self.Y) & 0xFF; +} + +fn Addr_ABX(self: *mos6502) u16 { + var addr: u16 = undefined; + var addrL: u16 = undefined; + var addrH: u16 = undefined; + + self.pc +%= 1; + addrL = self.Read(self.pc); + self.pc +%= 1; + addrH = self.Read(self.pc); + + addr = addrL +% (addrH << 8) + self.X; + return addr; +} + +fn Addr_ABY(self: *mos6502) u16 { + var addr: u16 = undefined; + var addrL: u16 = undefined; + var addrH: u16 = undefined; + + self.pc +%= 1; + addrL = self.Read(self.pc); + self.pc +%= 1; + addrH = self.Read(self.pc); + + addr = addrL +% (addrH << 8) + self.Y; + return addr; +} + +fn Addr_INX(self: *mos6502) u16 { + var zeroL: u16 = undefined; + var zeroH: u16 = undefined; + var addr: u16 = undefined; + + self.pc +%= 1; + zeroL = (self.Read(self.pc) +% self.X) & 0xFF; + zeroH = (zeroL +% 1) & 0xFF; + addr = self.Read(zeroL) +% (@as(u16, @intCast(self.Read(zeroH))) << 8); + + return addr; +} + +fn Addr_INY(self: *mos6502) u16 { + var zeroL: u16 = undefined; + var zeroH: u16 = undefined; + var addr: u16 = undefined; + + self.pc +%= 1; + zeroL = self.Read(self.pc); + zeroH = (zeroL +% 1) & 0xFF; + addr = self.Read(zeroL) +% (@as(u16, @intCast(self.Read(zeroH))) << 8) + self.Y; + + return addr; +} + +pub fn Reset(self: *mos6502) void { + self.A = self.reset_A; + self.Y = self.reset_Y; + self.X = self.reset_X; + + // load PC from reset vector + const pcl: u8 = self.Read(rstVectorL); + const pch: u8 = self.Read(rstVectorH); + self.pc = (pch << 8) +% pcl; + + self.sp = self.reset_sp; + + self.status = self.reset_status | CONSTANT | BREAK; + + self.illegalOpcode = false; +} + +fn StackPush(self: *mos6502, byte: u8) void { + self.Write(0x0100 +% @as(u16, @intCast(self.sp)), byte); + if (self.sp == 0x00) self.sp = 0xFF else self.sp -%= 1; +} + +fn StackPop(self: *mos6502) u8 { + if (self.sp == 0xFF) self.sp = 0x00 else self.sp +%= 1; + return self.Read(0x0100 +% @as(u16, @intCast(self.sp))); +} + +pub fn IRQ(self: *mos6502) void { + if (self.IF_INTERRUPT()) return; + + //SET_BREAK(0); + self.StackPush((self.pc >> 8) & 0xFF); + self.StackPush(self.pc & 0xFF); + self.StackPush((self.status & ~BREAK) | CONSTANT); + self.SET_INTERRUPT(1); + + // load PC from non-maskable interrupt vector + const pcl = self.Read(irqVectorL); + const pch = self.Read(irqVectorH); + self.pc = (pch << 8) + pcl; +} + +pub fn NMI(self: *mos6502) void { + //SET_BREAK(0); + self.StackPush((self.pc >> 8) & 0xFF); + self.StackPush(self.pc & 0xFF); + self.StackPush((self.status & ~BREAK) | CONSTANT); + self.SET_INTERRUPT(1); + + // load PC from non-maskable interrupt vector + const pcl = self.Read(nmiVectorL); + const pch = self.Read(nmiVectorH); + self.pc = (pch << 8) + pcl; +} + +pub fn Run(self: *mos6502, cyclesRemaning: *i32, cycleCount: *u64, cycleMethod: CycleMethod) void { + var opcode: u8 = undefined; + var instr: Instr = undefined; + + while (cyclesRemaning > 0 and !self.illegalOpcode) { + // fetch + self.pc +%= 1; + opcode = self.Read(self.pc); + + // decode + instr = self.InstrTable[opcode]; + + // execute + self.Exec(instr); + cycleCount +%= instr.cycles; + cyclesRemaning -%= if (cycleMethod == .CYCLE_COUNT) instr.cycles else 1; + + // run clock cycle callback + if (self.Cycle) |Cycle| { + for (0..instr.cycles) |_| { + Cycle(self); + } + } + } +} + +pub fn RunEternally(self: *mos6502) void { + var opcode: u8 = undefined; + var instr: Instr = undefined; + + while (!self.illegalOpcode) { + // fetch + self.pc +%= 1; + opcode = self.Read(self.pc); + + // decode + instr = self.InstrTable[opcode]; + + // execute + self.Exec(instr); + + // run clock cycle callback + if (self.Cycle) |Cycle| { + for (0..instr.cycles) |_| { + Cycle(self); + } + } + } +} + +fn Exec(self: *mos6502, i: Instr) void { + const src = i.addr(self); + i.code(self, src); +} + +fn Op_ILLEGAL(self: *mos6502, _: u16) void { + self.illegalOpcode = true; +} + +fn Op_ADC(self: *mos6502, src: u16) void { + const m = self.Read(src); + var tmp = m + self.A + @intFromBool(self.IF_CARRY()); + self.SET_ZERO(tmp & 0xFF == 0); + if (self.IF_DECIMAL()) { + if (((self.A & 0xF) + (m & 0xF) + @intFromBool(self.IF_CARRY())) > 9) tmp += 6; + self.SET_NEGATIVE(tmp & 0x80); + self.SET_OVERFLOW(!((self.A ^ m) & 0x80 != 0 and (self.A ^ tmp) & 0x80 != 0)); + if (tmp > 0x99) tmp +%= 96; + self.SET_CARRY(tmp > 0xFF); + } else { + self.SET_NEGATIVE(tmp & 0x80); + self.SET_OVERFLOW(!((self.A ^ m) & 0x80 != 0 and (self.A ^ tmp) & 0x80 != 0)); + self.SET_CARRY(tmp > 0xFF); + } + + self.A = tmp & 0xFF; +} + +fn Op_AND(self: *mos6502, src: u16) void { + const m = self.Read(src); + const res = m & self.A; + self.SET_NEGATIVE(res & 0x80); + self.SET_NEGATIVE(res == 0); + self.A = res; +} + +fn Op_ASL(self: *mos6502, src: u16) void { + var m = self.Read(src); + self.SET_CARRY(m & 0x80); + m <<= 1; + m &= 0xFF; + self.SET_NEGATIVE(m & 0x80); + self.SET_ZERO(m == 0); + self.Write(src, m); +} + +fn Op_ASL_ACC(self: *mos6502, _: u16) void { + var m = self.A; + self.SET_CARRY(m & 0x80); + m <<= 1; + m &= 0xFF; + self.SET_NEGATIVE(m & 0x80); + self.SET_ZERO(m == 0); + self.A = m; +} + +fn Op_BCC(self: *mos6502, src: u16) void { + if (!self.IF_CARRY()) + self.pc = src; +} + +fn Op_BCS(self: *mos6502, src: u16) void { + if (self.IF_CARRY()) + self.pc = src; +} + +fn Op_BEQ(self: *mos6502, src: u16) void { + if (self.IF_ZERO()) + self.pc = src; +} + +fn Op_BIT(self: *mos6502, src: u16) void { + const m = self.Read(src); + const res = m & self.A; + self.SET_NEGATIVE(res & 0x80); + self.status = (self.status & 0x3F) | (m & 0xC0) | CONSTANT | BREAK; + self.SET_ZERO(res == 0); +} + +fn Op_BMI(self: *mos6502, src: u16) void { + if (self.IF_NEGATIVE()) + self.pc = src; +} + +fn Op_BNE(self: *mos6502, src: u16) void { + if (!self.IF_ZERO()) + self.pc = src; +} + +fn Op_BPL(self: *mos6502, src: u16) void { + if (!self.IF_NEGATIVE()) + self.pc = src; +} + +fn Op_BRK(self: *mos6502, _: u16) void { + self.pc += 1; + self.StackPush(@truncate(self.pc >> 8)); + self.StackPush(@truncate(self.pc)); + self.StackPush(self.status | CONSTANT | BREAK); + self.SET_INTERRUPT(1); + self.pc = (@as(u16, @intCast(self.Read(irqVectorH))) << 8) + self.Read(irqVectorL); +} + +fn Op_BVC(self: *mos6502, src: u16) void { + if (!self.IF_OVERFLOW()) + self.pc = src; +} + +fn Op_BVS(self: *mos6502, src: u16) void { + if (self.IF_OVERFLOW()) + self.pc = src; +} + +fn Op_CLC(self: *mos6502, _: u16) void { + self.SET_CARRY(0); +} + +fn Op_CLD(self: *mos6502, _: u16) void { + self.SET_DECIMAL(0); +} + +fn Op_CLI(self: *mos6502, _: u16) void { + self.SET_INTERRUPT(0); +} + +fn Op_CLV(self: *mos6502, _: u16) void { + self.SET_OVERFLOW(0); +} + +fn Op_CMP(self: *mos6502, src: u16) void { + const tmp = self.A - self.Read(src); + self.SET_CARRY(tmp < 0x100); + self.SET_NEGATIVE(tmp & 0x80); + self.SET_ZERO(tmp & 0xFF == 0); +} + +fn Op_CPX(self: *mos6502, src: u16) void { + const tmp = self.X - self.Read(src); + self.SET_CARRY(tmp < 0x100); + self.SET_NEGATIVE(tmp & 0x80); + self.SET_ZERO(tmp & 0xFF == 0); +} + +fn Op_CPY(self: *mos6502, src: u16) void { + const tmp = self.Y - self.Read(src); + self.SET_CARRY(tmp < 0x100); + self.SET_NEGATIVE(tmp & 0x80); + self.SET_ZERO(tmp & 0xFF == 0); +} + +fn Op_DEC(self: *mos6502, src: u16) void { + var m = self.Read(src); + m = (m - 1) & 0xFF; + self.SET_NEGATIVE(m & 0x80); + self.SET_ZERO(m == 0); + self.Write(src, m); +} + +fn Op_DEX(self: *mos6502, _: u16) void { + var m = self.X; + m = (m - 1) & 0xFF; + self.SET_NEGATIVE(m & 0x80); + self.SET_ZERO(m == 0); + self.X = m; +} + +fn Op_DEY(self: *mos6502, _: u16) void { + var m = self.Y; + m = (m - 1) & 0xFF; + self.SET_NEGATIVE(m & 0x80); + self.SET_ZERO(m == 0); + self.Y = m; +} + +fn Op_EOR(self: *mos6502, src: u16) void { + var m = self.Read(src); + m = self.A ^ m; + self.SET_NEGATIVE(m & 0x80); + self.SET_ZERO(m == 0); + self.A = m; +} + +fn Op_INC(self: *mos6502, src: u16) void { + var m = self.Read(src); + m = (m + 1) & 0xFF; + self.SET_NEGATIVE(m & 0x80); + self.SET_ZERO(m == 0); + self.Write(src, m); +} + +fn Op_INX(self: *mos6502, _: u16) void { + var m = self.X; + m = (m + 1) & 0xFF; + self.SET_NEGATIVE(m & 0x80); + self.SET_ZERO(m == 0); + self.X = m; +} + +fn Op_INY(self: *mos6502, _: u16) void { + var m = self.Y; + m = (m + 1) & 0xFF; + self.SET_NEGATIVE(m & 0x80); + self.SET_ZERO(m == 0); + self.Y = m; +} + +fn Op_JMP(self: *mos6502, src: u16) void { + self.pc = src; +} + +fn Op_JSR(self: *mos6502, src: u16) void { + self.pc -= 1; + self.StackPush(@truncate(self.pc >> 8)); + self.StackPush(@truncate(self.pc)); + self.pc = src; +} + +fn Op_LDA(self: *mos6502, src: u16) void { + const m = self.Read(src); + self.SET_NEGATIVE(m & 0x80); + self.SET_ZERO(m == 0); + self.A = m; +} + +fn Op_LDX(self: *mos6502, src: u16) void { + const m = self.Read(src); + self.SET_NEGATIVE(m & 0x80); + self.SET_ZERO(m == 0); + self.X = m; +} + +fn Op_LDY(self: *mos6502, src: u16) void { + const m = self.Read(src); + self.SET_NEGATIVE(m & 0x80); + self.SET_ZERO(m == 0); + self.Y = m; +} + +fn Op_LSR(self: *mos6502, src: u16) void { + var m = self.Read(src); + self.SET_CARRY(m & 0x01); + m >>= 1; + self.SET_NEGATIVE(0); + self.SET_ZERO(m == 0); + self.A = m; +} + +fn Op_LSR_ACC(self: *mos6502, _: u16) void { + var m = self.A; + self.SET_CARRY(m & 0x01); + m >>= 1; + self.SET_NEGATIVE(0); + self.SET_ZERO(m == 0); + self.A = m; +} + +fn Op_NOP(_: *mos6502, _: u16) void {} + +fn Op_ORA(self: *mos6502, src: u16) void { + var m = self.Read(src); + m = self.A | m; + self.SET_NEGATIVE(m & 0x80); + self.SET_ZERO(m == 0); +} + +fn Op_PHA(self: *mos6502, _: u16) void { + self.StackPush(self.A); +} + +fn Op_PHP(self: *mos6502, _: u16) void { + self.StackPush(self.status | CONSTANT | BREAK); +} + +fn Op_PLA(self: *mos6502, _: u16) void { + self.A = self.StackPop(); + self.SET_NEGATIVE(self.A & 0x80); + self.SET_ZERO(self.A == 0); +} + +fn Op_PLP(self: *mos6502, _: u16) void { + self.status = self.StackPop() | CONSTANT | BREAK; +} + +fn Op_ROL(self: *mos6502, src: u16) void { + var m = self.Read(src); + m <<= 1; + if (self.IF_CARRY()) m |= 0x01; + self.SET_CARRY(m > 0xFF); + m &= 0xFF; + self.SET_NEGATIVE(m & 0x80); + self.SET_ZERO(m == 0); + self.Write(src, m); +} + +fn Op_ROL_ACC(self: *mos6502, _: u16) void { + var m = self.A; + m <<= 1; + if (self.IF_CARRY()) m |= 0x01; + self.SET_CARRY(m > 0xFF); + m &= 0xFF; + self.SET_NEGATIVE(m & 0x80); + self.SET_ZERO(m == 0); + self.A = m; +} + +fn Op_ROR(self: *mos6502, src: u16) void { + var m = self.Read(src); + if (self.IF_CARRY()) m |= 0x01; + self.SET_CARRY(m > 0xFF); + m >>= 1; + m &= 0xFF; + self.SET_NEGATIVE(m & 0x80); + self.SET_ZERO(m == 0); + self.Write(src, m); +} + +fn Op_ROR_ACC(self: *mos6502, _: u16) void { + var m = self.A; + if (self.IF_CARRY()) m |= 0x01; + self.SET_CARRY(m > 0xFF); + m >>= 1; + m &= 0xFF; + self.SET_NEGATIVE(m & 0x80); + self.SET_ZERO(m == 0); + self.A = m; +} + +fn Op_RTI(self: *mos6502, _: u16) void { + self.status = self.StackPop() | CONSTANT | BREAK; + const lo = self.StackPop(); + const hi = self.StackPop(); + + self.pc = (@as(u16, @intCast(hi)) << 8) | lo; +} + +fn Op_RTS(self: *mos6502, _: u16) void { + const lo = self.StackPop(); + const hi = self.StackPop(); + + self.pc = (@as(u16, @intCast(hi)) << 8) | lo; +} + +fn Op_SBC(self: *mos6502, src: u16) void { + const m = self.Read(src); + var tmp = self.A - m - @intFromBool(self.IF_CARRY()); + self.SET_NEGATIVE(tmp & 0x80); + self.SET_ZERO(tmp & 0xFF == 0); + self.SET_OVERFLOW(((self.A ^ tmp) & 0x80 != 0) and ((self.A ^ m) & 0x80 != 0)); + if (self.IF_DECIMAL()) { + if (((self.A & 0x0F) - @intFromBool(self.IF_CARRY())) < (m & 0x0F)) + tmp -= 6; + if (tmp > 0x99) + tmp -= 0x60; + } + self.SET_CARRY(tmp < 0x100); + self.A = (tmp & 0xFF); +} + +fn Op_SEC(self: *mos6502, _: u16) void { + self.SET_CARRY(1); +} + +fn Op_SED(self: *mos6502, _: u16) void { + self.SET_DECIMAL(1); +} + +fn Op_SEI(self: *mos6502, _: u16) void { + self.SET_INTERRUPT(1); +} + +fn Op_STA(self: *mos6502, src: u16) void { + self.Write(src, self.A); +} + +fn Op_STY(self: *mos6502, src: u16) void { + self.Write(src, self.Y); +} + +fn Op_STX(self: *mos6502, src: u16) void { + self.Write(src, self.X); +} + +fn Op_TAX(self: *mos6502, _: u16) void { + const m = self.A; + self.SET_NEGATIVE(m & 0x80); + self.SET_ZERO(m == 0); + self.X = m; +} + +fn Op_TAY(self: *mos6502, _: u16) void { + const m = self.A; + self.SET_NEGATIVE(m & 0x80); + self.SET_ZERO(m == 0); + self.Y = m; +} + +fn Op_TSX(self: *mos6502, _: u16) void { + const m = self.sp; + self.SET_NEGATIVE(m & 0x80); + self.SET_ZERO(m == 0); + self.X = m; +} + +fn Op_TXA(self: *mos6502, _: u16) void { + const m = self.X; + self.SET_NEGATIVE(m & 0x80); + self.SET_ZERO(m == 0); + self.A = m; +} + +fn Op_TXS(self: *mos6502, _: u16) void { + self.sp = self.X; +} + +fn Op_TYA(self: *mos6502, _: u16) void { + const m = self.Y; + self.SET_NEGATIVE(m & 0x80); + self.SET_ZERO(m == 0); + self.A = m; +} + +pub fn init(functions: Functions) mos6502 { + var mosInit = mos6502{ + .reset_A = 0x00, + .reset_X = 0x00, + .reset_Y = 0x00, + .reset_sp = 0xFD, + .reset_status = CONSTANT, + .Write = functions.BusWrite, + .Read = functions.BusRead, + .Cycle = functions.ClockCycle, + .illegalOpcode = false, + .InstrTable = undefined, + .A = 0x00, + .pc = 0x00, + .sp = 0x00, + .status = 0, + .X = 0x00, + .Y = 0x00, + }; + + var instr: Instr = undefined; + + instr.addr = &Addr_IMP; + instr.code = &Op_ILLEGAL; + + for (0..256) |i| { + mosInit.InstrTable[i] = instr; + } + + instr.addr = &Addr_IMM; + instr.code = &Op_ADC; + instr.cycles = 2; + mosInit.InstrTable[0x69] = instr; + instr.addr = &Addr_ABS; + instr.code = &Op_ADC; + instr.cycles = 4; + mosInit.InstrTable[0x6D] = instr; + instr.addr = &Addr_ZER; + instr.code = &Op_ADC; + instr.cycles = 3; + mosInit.InstrTable[0x65] = instr; + instr.addr = &Addr_INX; + instr.code = &Op_ADC; + instr.cycles = 6; + mosInit.InstrTable[0x61] = instr; + instr.addr = &Addr_INY; + instr.code = &Op_ADC; + instr.cycles = 6; + mosInit.InstrTable[0x71] = instr; + instr.addr = &Addr_ZEX; + instr.code = &Op_ADC; + instr.cycles = 4; + mosInit.InstrTable[0x75] = instr; + instr.addr = &Addr_ABX; + instr.code = &Op_ADC; + instr.cycles = 4; + mosInit.InstrTable[0x7D] = instr; + instr.addr = &Addr_ABY; + instr.code = &Op_ADC; + instr.cycles = 4; + mosInit.InstrTable[0x79] = instr; + + instr.addr = &Addr_IMM; + instr.code = &Op_AND; + instr.cycles = 2; + mosInit.InstrTable[0x29] = instr; + instr.addr = &Addr_ABS; + instr.code = &Op_AND; + instr.cycles = 4; + mosInit.InstrTable[0x2D] = instr; + instr.addr = &Addr_ZER; + instr.code = &Op_AND; + instr.cycles = 3; + mosInit.InstrTable[0x25] = instr; + instr.addr = &Addr_INX; + instr.code = &Op_AND; + instr.cycles = 6; + mosInit.InstrTable[0x21] = instr; + instr.addr = &Addr_INY; + instr.code = &Op_AND; + instr.cycles = 5; + mosInit.InstrTable[0x31] = instr; + instr.addr = &Addr_ZEX; + instr.code = &Op_AND; + instr.cycles = 4; + mosInit.InstrTable[0x35] = instr; + instr.addr = &Addr_ABX; + instr.code = &Op_AND; + instr.cycles = 4; + mosInit.InstrTable[0x3D] = instr; + instr.addr = &Addr_ABY; + instr.code = &Op_AND; + instr.cycles = 4; + mosInit.InstrTable[0x39] = instr; + + instr.addr = &Addr_ABS; + instr.code = &Op_ASL; + instr.cycles = 6; + mosInit.InstrTable[0x0E] = instr; + instr.addr = &Addr_ZER; + instr.code = &Op_ASL; + instr.cycles = 5; + mosInit.InstrTable[0x06] = instr; + instr.addr = &Addr_ACC; + instr.code = &Op_ASL_ACC; + instr.cycles = 2; + mosInit.InstrTable[0x0A] = instr; + instr.addr = &Addr_ZEX; + instr.code = &Op_ASL; + instr.cycles = 6; + mosInit.InstrTable[0x16] = instr; + instr.addr = &Addr_ABX; + instr.code = &Op_ASL; + instr.cycles = 7; + mosInit.InstrTable[0x1E] = instr; + + instr.addr = &Addr_REL; + instr.code = &Op_BCC; + instr.cycles = 2; + mosInit.InstrTable[0x90] = instr; + + instr.addr = &Addr_REL; + instr.code = &Op_BCS; + instr.cycles = 2; + mosInit.InstrTable[0xB0] = instr; + + instr.addr = &Addr_REL; + instr.code = &Op_BEQ; + instr.cycles = 2; + mosInit.InstrTable[0xF0] = instr; + + instr.addr = &Addr_ABS; + instr.code = &Op_BIT; + instr.cycles = 4; + mosInit.InstrTable[0x2C] = instr; + instr.addr = &Addr_ZER; + instr.code = &Op_BIT; + instr.cycles = 3; + mosInit.InstrTable[0x24] = instr; + + instr.addr = &Addr_REL; + instr.code = &Op_BMI; + instr.cycles = 2; + mosInit.InstrTable[0x30] = instr; + + instr.addr = &Addr_REL; + instr.code = &Op_BNE; + instr.cycles = 2; + mosInit.InstrTable[0xD0] = instr; + + instr.addr = &Addr_REL; + instr.code = &Op_BPL; + instr.cycles = 2; + mosInit.InstrTable[0x10] = instr; + + instr.addr = &Addr_IMP; + instr.code = &Op_BRK; + instr.cycles = 7; + mosInit.InstrTable[0x00] = instr; + + instr.addr = &Addr_REL; + instr.code = &Op_BVC; + instr.cycles = 2; + mosInit.InstrTable[0x50] = instr; + + instr.addr = &Addr_REL; + instr.code = &Op_BVS; + instr.cycles = 2; + mosInit.InstrTable[0x70] = instr; + + instr.addr = &Addr_IMP; + instr.code = &Op_CLC; + instr.cycles = 2; + mosInit.InstrTable[0x18] = instr; + + instr.addr = &Addr_IMP; + instr.code = &Op_CLD; + instr.cycles = 2; + mosInit.InstrTable[0xD8] = instr; + + instr.addr = &Addr_IMP; + instr.code = &Op_CLI; + instr.cycles = 2; + mosInit.InstrTable[0x58] = instr; + + instr.addr = &Addr_IMP; + instr.code = &Op_CLV; + instr.cycles = 2; + mosInit.InstrTable[0xB8] = instr; + + instr.addr = &Addr_IMM; + instr.code = &Op_CMP; + instr.cycles = 2; + mosInit.InstrTable[0xC9] = instr; + instr.addr = &Addr_ABS; + instr.code = &Op_CMP; + instr.cycles = 4; + mosInit.InstrTable[0xCD] = instr; + instr.addr = &Addr_ZER; + instr.code = &Op_CMP; + instr.cycles = 3; + mosInit.InstrTable[0xC5] = instr; + instr.addr = &Addr_INX; + instr.code = &Op_CMP; + instr.cycles = 6; + mosInit.InstrTable[0xC1] = instr; + instr.addr = &Addr_INY; + instr.code = &Op_CMP; + instr.cycles = 3; + mosInit.InstrTable[0xD1] = instr; + instr.addr = &Addr_ZEX; + instr.code = &Op_CMP; + instr.cycles = 4; + mosInit.InstrTable[0xD5] = instr; + instr.addr = &Addr_ABX; + instr.code = &Op_CMP; + instr.cycles = 4; + mosInit.InstrTable[0xDD] = instr; + instr.addr = &Addr_ABY; + instr.code = &Op_CMP; + instr.cycles = 4; + mosInit.InstrTable[0xD9] = instr; + + instr.addr = &Addr_IMM; + instr.code = &Op_CPX; + instr.cycles = 2; + mosInit.InstrTable[0xE0] = instr; + instr.addr = &Addr_ABS; + instr.code = &Op_CPX; + instr.cycles = 4; + mosInit.InstrTable[0xEC] = instr; + instr.addr = &Addr_ZER; + instr.code = &Op_CPX; + instr.cycles = 3; + mosInit.InstrTable[0xE4] = instr; + + instr.addr = &Addr_IMM; + instr.code = &Op_CPY; + instr.cycles = 2; + mosInit.InstrTable[0xC0] = instr; + instr.addr = &Addr_ABS; + instr.code = &Op_CPY; + instr.cycles = 4; + mosInit.InstrTable[0xCC] = instr; + instr.addr = &Addr_ZER; + instr.code = &Op_CPY; + instr.cycles = 3; + mosInit.InstrTable[0xC4] = instr; + + instr.addr = &Addr_ABS; + instr.code = &Op_DEC; + instr.cycles = 6; + mosInit.InstrTable[0xCE] = instr; + instr.addr = &Addr_ZER; + instr.code = &Op_DEC; + instr.cycles = 5; + mosInit.InstrTable[0xC6] = instr; + instr.addr = &Addr_ZEX; + instr.code = &Op_DEC; + instr.cycles = 6; + mosInit.InstrTable[0xD6] = instr; + instr.addr = &Addr_ABX; + instr.code = &Op_DEC; + instr.cycles = 7; + mosInit.InstrTable[0xDE] = instr; + + instr.addr = &Addr_IMP; + instr.code = &Op_DEX; + instr.cycles = 2; + mosInit.InstrTable[0xCA] = instr; + + instr.addr = &Addr_IMP; + instr.code = &Op_DEY; + instr.cycles = 2; + mosInit.InstrTable[0x88] = instr; + + instr.addr = &Addr_IMM; + instr.code = &Op_EOR; + instr.cycles = 2; + mosInit.InstrTable[0x49] = instr; + instr.addr = &Addr_ABS; + instr.code = &Op_EOR; + instr.cycles = 4; + mosInit.InstrTable[0x4D] = instr; + instr.addr = &Addr_ZER; + instr.code = &Op_EOR; + instr.cycles = 3; + mosInit.InstrTable[0x45] = instr; + instr.addr = &Addr_INX; + instr.code = &Op_EOR; + instr.cycles = 6; + mosInit.InstrTable[0x41] = instr; + instr.addr = &Addr_INY; + instr.code = &Op_EOR; + instr.cycles = 5; + mosInit.InstrTable[0x51] = instr; + instr.addr = &Addr_ZEX; + instr.code = &Op_EOR; + instr.cycles = 4; + mosInit.InstrTable[0x55] = instr; + instr.addr = &Addr_ABX; + instr.code = &Op_EOR; + instr.cycles = 4; + mosInit.InstrTable[0x5D] = instr; + instr.addr = &Addr_ABY; + instr.code = &Op_EOR; + instr.cycles = 4; + mosInit.InstrTable[0x59] = instr; + + instr.addr = &Addr_ABS; + instr.code = &Op_INC; + instr.cycles = 6; + mosInit.InstrTable[0xEE] = instr; + instr.addr = &Addr_ZER; + instr.code = &Op_INC; + instr.cycles = 5; + mosInit.InstrTable[0xE6] = instr; + instr.addr = &Addr_ZEX; + instr.code = &Op_INC; + instr.cycles = 6; + mosInit.InstrTable[0xF6] = instr; + instr.addr = &Addr_ABX; + instr.code = &Op_INC; + instr.cycles = 7; + mosInit.InstrTable[0xFE] = instr; + + instr.addr = &Addr_IMP; + instr.code = &Op_INX; + instr.cycles = 2; + mosInit.InstrTable[0xE8] = instr; + + instr.addr = &Addr_IMP; + instr.code = &Op_INY; + instr.cycles = 2; + mosInit.InstrTable[0xC8] = instr; + + instr.addr = &Addr_ABS; + instr.code = &Op_JMP; + instr.cycles = 3; + mosInit.InstrTable[0x4C] = instr; + instr.addr = &Addr_ABI; + instr.code = &Op_JMP; + instr.cycles = 5; + mosInit.InstrTable[0x6C] = instr; + + instr.addr = &Addr_ABS; + instr.code = &Op_JSR; + instr.cycles = 6; + mosInit.InstrTable[0x20] = instr; + + instr.addr = &Addr_IMM; + instr.code = &Op_LDA; + instr.cycles = 2; + mosInit.InstrTable[0xA9] = instr; + instr.addr = &Addr_ABS; + instr.code = &Op_LDA; + instr.cycles = 4; + mosInit.InstrTable[0xAD] = instr; + instr.addr = &Addr_ZER; + instr.code = &Op_LDA; + instr.cycles = 3; + mosInit.InstrTable[0xA5] = instr; + instr.addr = &Addr_INX; + instr.code = &Op_LDA; + instr.cycles = 6; + mosInit.InstrTable[0xA1] = instr; + instr.addr = &Addr_INY; + instr.code = &Op_LDA; + instr.cycles = 5; + mosInit.InstrTable[0xB1] = instr; + instr.addr = &Addr_ZEX; + instr.code = &Op_LDA; + instr.cycles = 4; + mosInit.InstrTable[0xB5] = instr; + instr.addr = &Addr_ABX; + instr.code = &Op_LDA; + instr.cycles = 4; + mosInit.InstrTable[0xBD] = instr; + instr.addr = &Addr_ABY; + instr.code = &Op_LDA; + instr.cycles = 4; + mosInit.InstrTable[0xB9] = instr; + + instr.addr = &Addr_IMM; + instr.code = &Op_LDX; + instr.cycles = 2; + mosInit.InstrTable[0xA2] = instr; + instr.addr = &Addr_ABS; + instr.code = &Op_LDX; + instr.cycles = 4; + mosInit.InstrTable[0xAE] = instr; + instr.addr = &Addr_ZER; + instr.code = &Op_LDX; + instr.cycles = 3; + mosInit.InstrTable[0xA6] = instr; + instr.addr = &Addr_ABY; + instr.code = &Op_LDX; + instr.cycles = 4; + mosInit.InstrTable[0xBE] = instr; + instr.addr = &Addr_ZEY; + instr.code = &Op_LDX; + instr.cycles = 4; + mosInit.InstrTable[0xB6] = instr; + + instr.addr = &Addr_IMM; + instr.code = &Op_LDY; + instr.cycles = 2; + mosInit.InstrTable[0xA0] = instr; + instr.addr = &Addr_ABS; + instr.code = &Op_LDY; + instr.cycles = 4; + mosInit.InstrTable[0xAC] = instr; + instr.addr = &Addr_ZER; + instr.code = &Op_LDY; + instr.cycles = 3; + mosInit.InstrTable[0xA4] = instr; + instr.addr = &Addr_ZEX; + instr.code = &Op_LDY; + instr.cycles = 4; + mosInit.InstrTable[0xB4] = instr; + instr.addr = &Addr_ABX; + instr.code = &Op_LDY; + instr.cycles = 4; + mosInit.InstrTable[0xBC] = instr; + + instr.addr = &Addr_ABS; + instr.code = &Op_LSR; + instr.cycles = 6; + mosInit.InstrTable[0x4E] = instr; + instr.addr = &Addr_ZER; + instr.code = &Op_LSR; + instr.cycles = 5; + mosInit.InstrTable[0x46] = instr; + instr.addr = &Addr_ACC; + instr.code = &Op_LSR_ACC; + instr.cycles = 2; + mosInit.InstrTable[0x4A] = instr; + instr.addr = &Addr_ZEX; + instr.code = &Op_LSR; + instr.cycles = 6; + mosInit.InstrTable[0x56] = instr; + instr.addr = &Addr_ABX; + instr.code = &Op_LSR; + instr.cycles = 7; + mosInit.InstrTable[0x5E] = instr; + + instr.addr = &Addr_IMP; + instr.code = &Op_NOP; + instr.cycles = 2; + mosInit.InstrTable[0xEA] = instr; + + instr.addr = &Addr_IMM; + instr.code = &Op_ORA; + instr.cycles = 2; + mosInit.InstrTable[0x09] = instr; + instr.addr = &Addr_ABS; + instr.code = &Op_ORA; + instr.cycles = 4; + mosInit.InstrTable[0x0D] = instr; + instr.addr = &Addr_ZER; + instr.code = &Op_ORA; + instr.cycles = 3; + mosInit.InstrTable[0x05] = instr; + instr.addr = &Addr_INX; + instr.code = &Op_ORA; + instr.cycles = 6; + mosInit.InstrTable[0x01] = instr; + instr.addr = &Addr_INY; + instr.code = &Op_ORA; + instr.cycles = 5; + mosInit.InstrTable[0x11] = instr; + instr.addr = &Addr_ZEX; + instr.code = &Op_ORA; + instr.cycles = 4; + mosInit.InstrTable[0x15] = instr; + instr.addr = &Addr_ABX; + instr.code = &Op_ORA; + instr.cycles = 4; + mosInit.InstrTable[0x1D] = instr; + instr.addr = &Addr_ABY; + instr.code = &Op_ORA; + instr.cycles = 4; + mosInit.InstrTable[0x19] = instr; + + instr.addr = &Addr_IMP; + instr.code = &Op_PHA; + instr.cycles = 3; + mosInit.InstrTable[0x48] = instr; + + instr.addr = &Addr_IMP; + instr.code = &Op_PHP; + instr.cycles = 3; + mosInit.InstrTable[0x08] = instr; + + instr.addr = &Addr_IMP; + instr.code = &Op_PLA; + instr.cycles = 4; + mosInit.InstrTable[0x68] = instr; + + instr.addr = &Addr_IMP; + instr.code = &Op_PLP; + instr.cycles = 4; + mosInit.InstrTable[0x28] = instr; + + instr.addr = &Addr_ABS; + instr.code = &Op_ROL; + instr.cycles = 6; + mosInit.InstrTable[0x2E] = instr; + instr.addr = &Addr_ZER; + instr.code = &Op_ROL; + instr.cycles = 5; + mosInit.InstrTable[0x26] = instr; + instr.addr = &Addr_ACC; + instr.code = &Op_ROL_ACC; + instr.cycles = 2; + mosInit.InstrTable[0x2A] = instr; + instr.addr = &Addr_ZEX; + instr.code = &Op_ROL; + instr.cycles = 6; + mosInit.InstrTable[0x36] = instr; + instr.addr = &Addr_ABX; + instr.code = &Op_ROL; + instr.cycles = 7; + mosInit.InstrTable[0x3E] = instr; + + instr.addr = &Addr_ABS; + instr.code = &Op_ROR; + instr.cycles = 6; + mosInit.InstrTable[0x6E] = instr; + instr.addr = &Addr_ZER; + instr.code = &Op_ROR; + instr.cycles = 5; + mosInit.InstrTable[0x66] = instr; + instr.addr = &Addr_ACC; + instr.code = &Op_ROR_ACC; + instr.cycles = 2; + mosInit.InstrTable[0x6A] = instr; + instr.addr = &Addr_ZEX; + instr.code = &Op_ROR; + instr.cycles = 6; + mosInit.InstrTable[0x76] = instr; + instr.addr = &Addr_ABX; + instr.code = &Op_ROR; + instr.cycles = 7; + mosInit.InstrTable[0x7E] = instr; + + instr.addr = &Addr_IMP; + instr.code = &Op_RTI; + instr.cycles = 6; + mosInit.InstrTable[0x40] = instr; + + instr.addr = &Addr_IMP; + instr.code = &Op_RTS; + instr.cycles = 6; + mosInit.InstrTable[0x60] = instr; + + instr.addr = &Addr_IMM; + instr.code = &Op_SBC; + instr.cycles = 2; + mosInit.InstrTable[0xE9] = instr; + instr.addr = &Addr_ABS; + instr.code = &Op_SBC; + instr.cycles = 4; + mosInit.InstrTable[0xED] = instr; + instr.addr = &Addr_ZER; + instr.code = &Op_SBC; + instr.cycles = 3; + mosInit.InstrTable[0xE5] = instr; + instr.addr = &Addr_INX; + instr.code = &Op_SBC; + instr.cycles = 6; + mosInit.InstrTable[0xE1] = instr; + instr.addr = &Addr_INY; + instr.code = &Op_SBC; + instr.cycles = 5; + mosInit.InstrTable[0xF1] = instr; + instr.addr = &Addr_ZEX; + instr.code = &Op_SBC; + instr.cycles = 4; + mosInit.InstrTable[0xF5] = instr; + instr.addr = &Addr_ABX; + instr.code = &Op_SBC; + instr.cycles = 4; + mosInit.InstrTable[0xFD] = instr; + instr.addr = &Addr_ABY; + instr.code = &Op_SBC; + instr.cycles = 4; + mosInit.InstrTable[0xF9] = instr; + + instr.addr = &Addr_IMP; + instr.code = &Op_SEC; + instr.cycles = 2; + mosInit.InstrTable[0x38] = instr; + + instr.addr = &Addr_IMP; + instr.code = &Op_SED; + instr.cycles = 2; + mosInit.InstrTable[0xF8] = instr; + + instr.addr = &Addr_IMP; + instr.code = &Op_SEI; + instr.cycles = 2; + mosInit.InstrTable[0x78] = instr; + + instr.addr = &Addr_ABS; + instr.code = &Op_STA; + instr.cycles = 4; + mosInit.InstrTable[0x8D] = instr; + instr.addr = &Addr_ZER; + instr.code = &Op_STA; + instr.cycles = 3; + mosInit.InstrTable[0x85] = instr; + instr.addr = &Addr_INX; + instr.code = &Op_STA; + instr.cycles = 6; + mosInit.InstrTable[0x81] = instr; + instr.addr = &Addr_INY; + instr.code = &Op_STA; + instr.cycles = 6; + mosInit.InstrTable[0x91] = instr; + instr.addr = &Addr_ZEX; + instr.code = &Op_STA; + instr.cycles = 4; + mosInit.InstrTable[0x95] = instr; + instr.addr = &Addr_ABX; + instr.code = &Op_STA; + instr.cycles = 5; + mosInit.InstrTable[0x9D] = instr; + instr.addr = &Addr_ABY; + instr.code = &Op_STA; + instr.cycles = 5; + mosInit.InstrTable[0x99] = instr; + + instr.addr = &Addr_ABS; + instr.code = &Op_STX; + instr.cycles = 4; + mosInit.InstrTable[0x8E] = instr; + instr.addr = &Addr_ZER; + instr.code = &Op_STX; + instr.cycles = 3; + mosInit.InstrTable[0x86] = instr; + instr.addr = &Addr_ZEY; + instr.code = &Op_STX; + instr.cycles = 4; + mosInit.InstrTable[0x96] = instr; + + instr.addr = &Addr_ABS; + instr.code = &Op_STY; + instr.cycles = 4; + mosInit.InstrTable[0x8C] = instr; + instr.addr = &Addr_ZER; + instr.code = &Op_STY; + instr.cycles = 3; + mosInit.InstrTable[0x84] = instr; + instr.addr = &Addr_ZEX; + instr.code = &Op_STY; + instr.cycles = 4; + mosInit.InstrTable[0x94] = instr; + + instr.addr = &Addr_IMP; + instr.code = &Op_TAX; + instr.cycles = 2; + mosInit.InstrTable[0xAA] = instr; + + instr.addr = &Addr_IMP; + instr.code = &Op_TAY; + instr.cycles = 2; + mosInit.InstrTable[0xA8] = instr; + + instr.addr = &Addr_IMP; + instr.code = &Op_TSX; + instr.cycles = 2; + mosInit.InstrTable[0xBA] = instr; + + instr.addr = &Addr_IMP; + instr.code = &Op_TXA; + instr.cycles = 2; + mosInit.InstrTable[0x8A] = instr; + + instr.addr = &Addr_IMP; + instr.code = &Op_TXS; + instr.cycles = 2; + mosInit.InstrTable[0x9A] = instr; + + instr.addr = &Addr_IMP; + instr.code = &Op_TYA; + instr.cycles = 2; + mosInit.InstrTable[0x98] = instr; + + return mosInit; +}