mirror of
https://github.com/Luigi30/FruitMachine-Swift.git
synced 2025-02-06 17:30:45 +00:00
optimizations, refactoring, cleanup, fixing warnings, all kinds of stuff
This commit is contained in:
parent
45e5c3c658
commit
3bb4eed9d1
@ -369,7 +369,7 @@
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = macosx;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@ -428,10 +428,12 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = FruitMachine/FruitMachine.entitlements;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
GENERATE_PROFILING_CODE = YES;
|
||||
INFOPLIST_FILE = FruitMachine/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.luigithirty.FruitMachine;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 4.0;
|
||||
};
|
||||
name = Debug;
|
||||
@ -442,10 +444,12 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = FruitMachine/FruitMachine.entitlements;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
GENERATE_PROFILING_CODE = YES;
|
||||
INFOPLIST_FILE = FruitMachine/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.luigithirty.FruitMachine;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
SWIFT_VERSION = 4.0;
|
||||
};
|
||||
name = Release;
|
||||
|
@ -58,26 +58,30 @@ class AppleI: NSObject {
|
||||
}
|
||||
|
||||
func runFrame() {
|
||||
let startTime = CFAbsoluteTimeGetCurrent()
|
||||
|
||||
CPU.sharedInstance.cycles = 0
|
||||
CPU.sharedInstance.cyclesInBatch = AppleI.CYCLES_PER_BATCH
|
||||
CPU.sharedInstance.runCyclesBatch()
|
||||
|
||||
let timeElapsed = CFAbsoluteTimeGetCurrent() - startTime
|
||||
print("Time elapsed for runFrame: \(timeElapsed) s.")
|
||||
|
||||
//update the video display
|
||||
CVPixelBufferLockBaseAddress(emulatorViewDelegate.pixels!, CVPixelBufferLockFlags(rawValue: 0))
|
||||
let pixelBase = CVPixelBufferGetBaseAddress(emulatorViewDelegate.pixels!)
|
||||
let buf = pixelBase?.assumingMemoryBound(to: BitmapPixelsBE555.PixelData.self)
|
||||
|
||||
for (cellNum, character) in terminal.characters.enumerated() {
|
||||
emulatorViewDelegate.putCharacterPixels(buffer: buf,
|
||||
charPixels: cg.getCharacterPixels(charIndex: character),
|
||||
pixelPosition: emulatorViewDelegate.getPixelOffset(charCellIndex: cellNum))
|
||||
emulatorViewDelegate.putGlyph(buffer: buf,
|
||||
glyph: cg.glyphs[Int(cg.asciiToAppleCharIndex(ascii: character))],
|
||||
pixelPosition: emulatorViewDelegate.getPixelOffset(charCellIndex: cellNum))
|
||||
}
|
||||
|
||||
CVPixelBufferUnlockBaseAddress(emulatorViewDelegate.pixels!, CVPixelBufferLockFlags(rawValue: 0))
|
||||
|
||||
emulatorView.setNeedsDisplay(emulatorView.frame)
|
||||
emulatorView.display()
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -40,17 +40,18 @@ class AppleIBitmapDisplay: NSObject, CALayerDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
func putCharacterPixels(buffer: UnsafeMutablePointer<BitmapPixelsBE555.PixelData>?, charPixels: [UInt8], pixelPosition: CGPoint) {
|
||||
func putGlyph(buffer: UnsafeMutablePointer<BitmapPixelsBE555.PixelData>?, glyph: Glyph, pixelPosition: CGPoint) {
|
||||
//You better have locked the buffer before getting here...
|
||||
|
||||
//Calculate the offset to reach the desired position.
|
||||
let baseOffset = scanlineOffsets[Int(pixelPosition.y)] + Int(pixelPosition.x)
|
||||
|
||||
for charY in 0..<CharacterGenerator.CHAR_HEIGHT {
|
||||
let offsetY = AppleIBitmapDisplay.PIXEL_WIDTH * charY
|
||||
let offset = baseOffset + AppleIBitmapDisplay.PIXEL_WIDTH * charY
|
||||
let glyphOffsetY = (charY * 8)
|
||||
|
||||
for charX in 0..<8 {
|
||||
buffer![baseOffset + offsetY + 7 - charX] = (charPixels[charY] & UInt8(1 << charX)) > 0 ? BitmapPixelsBE555.ARGBWhite : BitmapPixelsBE555.ARGBBlack
|
||||
buffer![offset + 7 - charX] = glyph.pixels[glyphOffsetY + charX]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,8 +18,8 @@ class BitmapPixels: NSObject {
|
||||
static let bitsPerPixel: UInt = 8
|
||||
static let colorSpace = CGColorSpaceCreateDeviceRGB()
|
||||
|
||||
static let ColorBlack = PixelData(data: 0b11000000)
|
||||
static let ColorWhite = PixelData(data: 0b11111111)
|
||||
static let Black = PixelData(data: 0b11000000)
|
||||
static let White = PixelData(data: 0b11111111)
|
||||
}
|
||||
|
||||
class BitmapPixelsARGB32 : NSObject {
|
||||
@ -34,8 +34,8 @@ class BitmapPixelsARGB32 : NSObject {
|
||||
static let bitsPerPixel: UInt = 32
|
||||
static let colorSpace = CGColorSpaceCreateDeviceRGB()
|
||||
|
||||
static let ARGBWhite = PixelData(a: 255, r: 200, g: 200, b: 200)
|
||||
static let ARGBBlack = PixelData(a: 255, r: 0, g: 0, b: 0)
|
||||
static let White = PixelData(a: 255, r: 200, g: 200, b: 200)
|
||||
static let Black = PixelData(a: 255, r: 0, g: 0, b: 0)
|
||||
}
|
||||
|
||||
class BitmapPixelsBE555 : NSObject {
|
||||
@ -47,6 +47,6 @@ class BitmapPixelsBE555 : NSObject {
|
||||
static let bitsPerPixel: UInt = 16
|
||||
static let colorSpace = CGColorSpaceCreateDeviceRGB()
|
||||
|
||||
static let ARGBWhite = PixelData(data: 0b1111111101111111)
|
||||
static let ARGBBlack = PixelData(data: 0b0000000000000000)
|
||||
static let White = PixelData(data: 0b1111111101111111)
|
||||
static let Black = PixelData(data: 0b0000000000000000)
|
||||
}
|
||||
|
@ -10,20 +10,34 @@ import Cocoa
|
||||
|
||||
//The character generator ROM contains 64 8x5 glyphs.
|
||||
|
||||
struct Glyph {
|
||||
var pixels: [BitmapPixelsBE555.PixelData] = [BitmapPixelsBE555.PixelData]()
|
||||
|
||||
init(inPixels: [BitmapPixelsBE555.PixelData]) {
|
||||
pixels = inPixels
|
||||
}
|
||||
}
|
||||
|
||||
class CharacterGenerator: NSObject {
|
||||
static let CHAR_WIDTH = 5
|
||||
static let CHAR_HEIGHT = 8
|
||||
|
||||
var ROM: [UInt8]
|
||||
var glyphs: [Glyph]
|
||||
|
||||
init(romPath: String) {
|
||||
ROM = [UInt8](repeating: 0xCC, count: 512)
|
||||
glyphs = [Glyph](repeating: Glyph(inPixels: [BitmapPixelsBE555.PixelData]()), count: 64)
|
||||
|
||||
super.init()
|
||||
loadROM(path: romPath)
|
||||
|
||||
for index in 0..<64 {
|
||||
glyphs[index] = Glyph(inPixels: getCharacterPixels(charIndex: UInt8(index)))
|
||||
}
|
||||
}
|
||||
|
||||
func loadROM(path: String) {
|
||||
private func loadROM(path: String) {
|
||||
do {
|
||||
let fileContent: NSData = try NSData(contentsOfFile: path)
|
||||
fileContent.getBytes(&ROM, range: NSRange(location: 0, length: 512))
|
||||
@ -32,19 +46,30 @@ class CharacterGenerator: NSObject {
|
||||
}
|
||||
}
|
||||
|
||||
func getCharacterPixels(charIndex: UInt8) -> [UInt8] {
|
||||
private func getCharacterPixels(charIndex: UInt8) -> [BitmapPixelsBE555.PixelData] {
|
||||
var pixelArray = [UInt8](repeating: 0x00, count: CharacterGenerator.CHAR_HEIGHT)
|
||||
|
||||
/* Instead of ignoring ASCII bit b6, we ignore bit b5. At the same time ASCII bit b6 must be inverted before it is fed to the character ROM. This way the entire character range from $40 to $7F will end up in the range $00 to $1F (twice of course). Now lower case characters are automatically translated into their corresponding upper case bit maps.
|
||||
*/
|
||||
|
||||
let convertedCharIndex = (charIndex & 0x1f) | (((charIndex ^ 0x40) & 0x40) >> 1)
|
||||
|
||||
//Don't convert the character indexes if we're populating the glyphs array.
|
||||
for scanlineIndex in 0..<CharacterGenerator.CHAR_HEIGHT {
|
||||
pixelArray[scanlineIndex] = ROM[scanlineIndex + (Int(convertedCharIndex) * CharacterGenerator.CHAR_HEIGHT)]
|
||||
pixelArray[scanlineIndex] = ROM[scanlineIndex + (Int(charIndex) * CharacterGenerator.CHAR_HEIGHT)]
|
||||
}
|
||||
|
||||
return pixelArray
|
||||
var glyphPixels = [BitmapPixelsBE555.PixelData]()
|
||||
|
||||
for charY in 0..<CharacterGenerator.CHAR_HEIGHT {
|
||||
for charX in 0..<8 {
|
||||
glyphPixels.append(pixelArray[Int(charY)] & (1 << charX) > 0 ? BitmapPixelsBE555.White : BitmapPixelsBE555.Black)
|
||||
}
|
||||
}
|
||||
|
||||
return glyphPixels
|
||||
}
|
||||
|
||||
func asciiToAppleCharIndex(ascii: UInt8) -> UInt8 {
|
||||
return (ascii & 0x1f) | (((ascii ^ 0x40) & 0x40) >> 1)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -111,7 +111,23 @@ struct StatusRegister {
|
||||
}
|
||||
}
|
||||
|
||||
class CPU: NSObject {
|
||||
final class CPU: NSObject {
|
||||
enum AddressingMode {
|
||||
case accumulator
|
||||
case immediate
|
||||
case implied
|
||||
case relative
|
||||
case absolute
|
||||
case zeropage
|
||||
case indirect
|
||||
case absolute_indexed_x
|
||||
case absolute_indexed_y
|
||||
case zeropage_indexed_x
|
||||
case zeropage_indexed_y
|
||||
case indexed_indirect
|
||||
case indirect_indexed
|
||||
}
|
||||
|
||||
let NMI_VECTOR: UInt16 = 0xFFFA
|
||||
let RESET_VECTOR: UInt16 = 0xFFFC
|
||||
let IRQ_VECTOR: UInt16 = 0xFFFE
|
||||
@ -196,7 +212,7 @@ class CPU: NSObject {
|
||||
|
||||
}
|
||||
|
||||
func executeNextInstruction() throws {
|
||||
final func executeNextInstruction() throws {
|
||||
instruction_register = memoryInterface.readByte(offset: program_counter)
|
||||
let operation = InstructionTable[instruction_register]
|
||||
if(operation == nil) {
|
||||
@ -241,7 +257,7 @@ class CPU: NSObject {
|
||||
}
|
||||
|
||||
/* Running */
|
||||
func cpuStep() {
|
||||
final func cpuStep() {
|
||||
do {
|
||||
try executeNextInstruction()
|
||||
} catch CPUExceptions.invalidInstruction {
|
||||
@ -252,11 +268,9 @@ class CPU: NSObject {
|
||||
}
|
||||
|
||||
func runCyclesBatch() {
|
||||
let startTime = CFAbsoluteTimeGetCurrent()
|
||||
|
||||
isRunning = true
|
||||
|
||||
while(!outOfCycles() && isRunning) {
|
||||
while(!outOfCycles()) {
|
||||
cpuStep()
|
||||
|
||||
if (breakpoints.contains(program_counter)) {
|
||||
@ -264,9 +278,6 @@ class CPU: NSObject {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
let timeElapsed = CFAbsoluteTimeGetCurrent() - startTime
|
||||
print("Time elapsed for runFrame: \(timeElapsed) s.")
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ class DebuggerViewController: NSViewController {
|
||||
|
||||
var disassembly: [Disassembly] = [Disassembly]()
|
||||
|
||||
func highlightCurrentInstruction() -> Bool {
|
||||
@discardableResult func highlightCurrentInstruction() -> Bool {
|
||||
for (index, instruction) in disassembly.enumerated() {
|
||||
if(instruction.address == cpuInstance.program_counter) {
|
||||
debuggerTableView.selectRowIndexes(NSIndexSet(index: index) as IndexSet, byExtendingSelection: false)
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
import Cocoa
|
||||
|
||||
class MemoryInterface: NSObject {
|
||||
final class MemoryInterface: NSObject {
|
||||
|
||||
fileprivate var memory: [UInt8]
|
||||
|
||||
@ -43,7 +43,7 @@ class MemoryInterface: NSObject {
|
||||
if(!bypassOverrides) {
|
||||
for override in write_overrides {
|
||||
if case override.rangeStart ... override.rangeEnd = offset {
|
||||
override.action(CPU.sharedInstance, value)
|
||||
_ = override.action(CPU.sharedInstance, value)
|
||||
if(!override.doWrite) {
|
||||
return
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ import Cocoa
|
||||
/* A ReadOverride is special behavior that occurs when a memory address is read.
|
||||
Memory-mapped registers, peripherals, etc. */
|
||||
|
||||
class ReadOverride: MemoryOverride {
|
||||
final class ReadOverride: MemoryOverride {
|
||||
let doRead: Bool //do we write anyway?
|
||||
|
||||
init(start: UInt16, end: UInt16, readAnyway: Bool, action: @escaping (AnyObject, UInt8?) -> UInt8?) {
|
||||
|
@ -11,7 +11,7 @@ import Cocoa
|
||||
/* A ReadOverride is special behavior that occurs when a memory address is written.
|
||||
Memory-mapped registers, peripherals, etc. */
|
||||
|
||||
class WriteOverride: MemoryOverride {
|
||||
final class WriteOverride: MemoryOverride {
|
||||
let doWrite: Bool //do we write anyway?
|
||||
|
||||
init(start: UInt16, end: UInt16, writeAnyway: Bool, action: @escaping (AnyObject, UInt8?) -> UInt8?) {
|
||||
|
@ -8,31 +8,15 @@
|
||||
|
||||
import Cocoa
|
||||
|
||||
enum AddressingMode {
|
||||
case accumulator
|
||||
case immediate
|
||||
case implied
|
||||
case relative
|
||||
case absolute
|
||||
case zeropage
|
||||
case indirect
|
||||
case absolute_indexed_x
|
||||
case absolute_indexed_y
|
||||
case zeropage_indexed_x
|
||||
case zeropage_indexed_y
|
||||
case indexed_indirect
|
||||
case indirect_indexed
|
||||
}
|
||||
|
||||
class CPUInstruction: NSObject {
|
||||
final class CPUInstruction: NSObject {
|
||||
let mnemonic: String //The mnemonic for this instruction.
|
||||
let cycles: Int //How many cycles does this instruction take?
|
||||
let bytes: Int //How many bytes long is this instruction?
|
||||
let addressingMode: AddressingMode //The addressing mode of this instruction.
|
||||
let addressingMode: CPU.AddressingMode //The addressing mode of this instruction.
|
||||
|
||||
let action: (CPU, AddressingMode) -> Void //A closure that describes this function's action.
|
||||
let action: (CPU, CPU.AddressingMode) -> Void //A closure that describes this function's action.
|
||||
|
||||
init(mnemonic: String, cycles: Int, bytes: Int, addressingMode: AddressingMode, action: @escaping (CPU, AddressingMode) -> Void) {
|
||||
init(mnemonic: String, cycles: Int, bytes: Int, addressingMode: CPU.AddressingMode, action: @escaping (CPU, CPU.AddressingMode) -> Void) {
|
||||
self.mnemonic = mnemonic
|
||||
self.cycles = cycles
|
||||
self.bytes = bytes
|
||||
|
@ -10,24 +10,24 @@ import Cocoa
|
||||
|
||||
extension CPU {
|
||||
|
||||
func popByte() -> UInt8 {
|
||||
fileprivate func popByte() -> UInt8 {
|
||||
stack_pointer = stack_pointer &+ 1
|
||||
return memoryInterface.readByte(offset: stackPointerAsUInt16())
|
||||
}
|
||||
|
||||
func popWord() -> UInt16 {
|
||||
fileprivate func popWord() -> UInt16 {
|
||||
let low = popByte()
|
||||
let high = popByte()
|
||||
|
||||
return (UInt16(high) << 8) | UInt16(low)
|
||||
}
|
||||
|
||||
func pushByte(data: UInt8) -> Void {
|
||||
fileprivate func pushByte(data: UInt8) -> Void {
|
||||
memoryInterface.writeByte(offset: stackPointerAsUInt16(), value: data)
|
||||
stack_pointer = stack_pointer &- 1
|
||||
}
|
||||
|
||||
func pushWord(data: UInt16) -> Void {
|
||||
fileprivate func pushWord(data: UInt16) -> Void {
|
||||
let low = UInt8(data & 0x00FF)
|
||||
let high = UInt8((data & 0xFF00) >> 8)
|
||||
|
||||
@ -35,11 +35,11 @@ extension CPU {
|
||||
pushByte(data: low)
|
||||
}
|
||||
|
||||
func stackPointerAsUInt16() -> UInt16 {
|
||||
fileprivate func stackPointerAsUInt16() -> UInt16 {
|
||||
return 0x0100 | UInt16(stack_pointer);
|
||||
}
|
||||
|
||||
func doBranch() {
|
||||
fileprivate func doBranch() {
|
||||
let distance = Int8(bitPattern: getOperandByte())
|
||||
|
||||
if(distance < 0) {
|
||||
@ -67,7 +67,7 @@ extension CPU {
|
||||
}
|
||||
}
|
||||
|
||||
func getOperandByteForAddressingMode(state: CPU, mode: AddressingMode) -> UInt8 {
|
||||
private func getOperandByteForAddressingMode(state: CPU, mode: CPU.AddressingMode) -> UInt8 {
|
||||
switch (mode) {
|
||||
|
||||
case .immediate:
|
||||
@ -81,52 +81,46 @@ func getOperandByteForAddressingMode(state: CPU, mode: AddressingMode) -> UInt8
|
||||
return state.memoryInterface.readByte(offset: UInt16(state.getOperandByte() &+ state.index_y) & 0x00FF)
|
||||
|
||||
case .absolute:
|
||||
let word: UInt16 = state.getOperandWord()
|
||||
return state.memoryInterface.readByte(offset: word)
|
||||
return state.memoryInterface.readByte(offset: state.getOperandWord())
|
||||
case .absolute_indexed_x:
|
||||
return state.memoryInterface.readByte(offset: state.getOperandWord() &+ UInt16(state.index_x))
|
||||
case .absolute_indexed_y:
|
||||
return state.memoryInterface.readByte(offset: state.getOperandWord() &+ UInt16(state.index_y))
|
||||
|
||||
case .indexed_indirect:
|
||||
let zp: UInt8 = state.memoryInterface.readByte(offset: UInt16(state.program_counter + 1))
|
||||
//read from (ZP)
|
||||
let pointer: UInt16 = state.memoryInterface.readWord(offset: UInt16(zp &+ state.index_x))
|
||||
return state.memoryInterface.readByte(offset: pointer)
|
||||
return state.memoryInterface.readByte(offset: state.memoryInterface.readWord(offset: UInt16(state.memoryInterface.readByte(offset: UInt16(state.program_counter + 1)) &+ state.index_x)))
|
||||
case .indirect_indexed:
|
||||
let zp: UInt8 = state.memoryInterface.readByte(offset: UInt16(state.program_counter + 1))
|
||||
let pointer: UInt16 = state.memoryInterface.readWord(offset: UInt16(zp)) &+ UInt16(state.index_y)
|
||||
return state.memoryInterface.readByte(offset: pointer)
|
||||
return state.memoryInterface.readByte(offset: state.memoryInterface.readWord(offset: UInt16(state.memoryInterface.readByte(offset: UInt16(state.program_counter + 1)))) &+ UInt16(state.index_y))
|
||||
default:
|
||||
print("Called getOperand: UInt8 on an instruction that expects a UInt16.")
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func getOperandAddressForAddressingMode(state: CPU, mode: AddressingMode) -> UInt16 {
|
||||
private func getOperandAddressForAddressingMode(state: CPU, mode: CPU.AddressingMode) -> UInt16 {
|
||||
//Function that will provide a 16-bit operand to instructions.
|
||||
//All instructions have 2 data bytes, little-endian.
|
||||
|
||||
switch(mode) {
|
||||
case .zeropage:
|
||||
return UInt16(0x0000 + (state.memoryInterface.readByte(offset: state.program_counter + 1)))
|
||||
return UInt16(0x0000 &+ (state.memoryInterface.readByte(offset: state.program_counter &+ 1)))
|
||||
case .zeropage_indexed_x:
|
||||
return UInt16(0x0000 + (state.memoryInterface.readByte(offset: state.program_counter + 1) &+ state.index_x))
|
||||
return UInt16(0x0000 &+ (state.memoryInterface.readByte(offset: state.program_counter &+ 1) &+ state.index_x))
|
||||
case .zeropage_indexed_y:
|
||||
return UInt16(0x0000 + (state.memoryInterface.readByte(offset: state.program_counter + 1) &+ state.index_y))
|
||||
return UInt16(0x0000 &+ (state.memoryInterface.readByte(offset: state.program_counter &+ 1) &+ state.index_y))
|
||||
case .absolute:
|
||||
return state.getOperandWord()
|
||||
case .absolute_indexed_x:
|
||||
return state.getOperandWord() + state.index_x
|
||||
return state.getOperandWord() &+ UInt16(state.index_x)
|
||||
case .absolute_indexed_y:
|
||||
return state.getOperandWord() + state.index_y
|
||||
return state.getOperandWord() &+ UInt16(state.index_y)
|
||||
case .indexed_indirect:
|
||||
let zp: UInt8 = state.memoryInterface.readByte(offset: UInt16(state.program_counter + 1))
|
||||
let zp: UInt8 = state.memoryInterface.readByte(offset: UInt16(state.program_counter &+ 1))
|
||||
//read from (ZP)
|
||||
let pointer: UInt16 = state.memoryInterface.readWord(offset: UInt16(zp &+ state.index_x))
|
||||
return pointer
|
||||
case .indirect_indexed:
|
||||
let zp: UInt8 = state.memoryInterface.readByte(offset: UInt16(state.program_counter + 1))
|
||||
let zp: UInt8 = state.memoryInterface.readByte(offset: UInt16(state.program_counter &+ 1))
|
||||
let pointer: UInt16 = state.memoryInterface.readWord(offset: UInt16(zp)) &+ UInt16(state.index_y)
|
||||
return pointer
|
||||
case .indirect:
|
||||
@ -137,7 +131,7 @@ func getOperandAddressForAddressingMode(state: CPU, mode: AddressingMode) -> UIn
|
||||
}
|
||||
}
|
||||
|
||||
func hex2bcd(hex: UInt8) -> UInt8 {
|
||||
fileprivate func hex2bcd(hex: UInt8) -> UInt8 {
|
||||
var y: UInt8 = (hex / 10) << 4
|
||||
y = y | (hex % 10)
|
||||
return y
|
||||
@ -145,7 +139,7 @@ func hex2bcd(hex: UInt8) -> UInt8 {
|
||||
|
||||
/* */
|
||||
|
||||
class Opcodes: NSObject {
|
||||
final class Opcodes: NSObject {
|
||||
|
||||
static func _Add(state: CPU, operand: UInt8, isSubtract: Bool) {
|
||||
if(state.accumulator == 0xFF) {
|
||||
@ -167,11 +161,11 @@ class Opcodes: NSObject {
|
||||
state.accumulator = t8
|
||||
}
|
||||
|
||||
static func ADC(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func ADC(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
_Add(state: state, operand: UInt8(getOperandByteForAddressingMode(state: state, mode: addressingMode)), isSubtract: false)
|
||||
}
|
||||
|
||||
static func SBC(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func SBC(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
let operand = UInt8(getOperandByteForAddressingMode(state: state, mode: addressingMode))
|
||||
var t16: UInt16 = UInt16(state.accumulator &- operand) &- UInt16((state.status_register.carry ? UInt8(0) : UInt8(1)))
|
||||
let t8: UInt8 = UInt8(t16 & 0xFF)
|
||||
@ -190,100 +184,100 @@ class Opcodes: NSObject {
|
||||
state.updateNegativeFlag(value: t8)
|
||||
}
|
||||
|
||||
static func LDA(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func LDA(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
state.accumulator = getOperandByteForAddressingMode(state: state, mode: addressingMode)
|
||||
|
||||
state.updateZeroFlag(value: state.accumulator)
|
||||
state.updateNegativeFlag(value: state.accumulator)
|
||||
}
|
||||
|
||||
static func LDX(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func LDX(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
state.index_x = getOperandByteForAddressingMode(state: state, mode: addressingMode)
|
||||
|
||||
state.updateZeroFlag(value: state.index_x)
|
||||
state.updateNegativeFlag(value: state.index_x)
|
||||
}
|
||||
|
||||
static func LDY(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func LDY(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
state.index_y = getOperandByteForAddressingMode(state: state, mode: addressingMode)
|
||||
|
||||
state.updateZeroFlag(value: state.index_y)
|
||||
state.updateNegativeFlag(value: state.index_y)
|
||||
}
|
||||
|
||||
static func STA(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func STA(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
let address: UInt16 = getOperandAddressForAddressingMode(state: state, mode: addressingMode)
|
||||
state.memoryInterface.writeByte(offset: address, value: state.accumulator)
|
||||
}
|
||||
|
||||
static func STX(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func STX(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
let address: UInt16 = getOperandAddressForAddressingMode(state: state, mode: addressingMode)
|
||||
state.memoryInterface.writeByte(offset: address, value: state.index_x)
|
||||
}
|
||||
|
||||
static func STY(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func STY(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
let address: UInt16 = getOperandAddressForAddressingMode(state: state, mode: addressingMode)
|
||||
state.memoryInterface.writeByte(offset: address, value: state.index_y)
|
||||
}
|
||||
|
||||
//Register instructions
|
||||
static func TAX(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func TAX(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
state.index_x = state.accumulator
|
||||
|
||||
state.updateZeroFlag(value: state.index_x);
|
||||
state.updateNegativeFlag(value: state.index_x);
|
||||
}
|
||||
|
||||
static func TXA(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func TXA(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
state.accumulator = state.index_x
|
||||
|
||||
state.updateZeroFlag(value: state.accumulator);
|
||||
state.updateNegativeFlag(value: state.accumulator);
|
||||
}
|
||||
|
||||
static func DEX(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func DEX(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
state.index_x = state.index_x &- 1
|
||||
|
||||
state.updateZeroFlag(value: state.index_x);
|
||||
state.updateNegativeFlag(value: state.index_x);
|
||||
}
|
||||
|
||||
static func INX(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func INX(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
state.index_x = state.index_x &+ 1
|
||||
|
||||
state.updateZeroFlag(value: state.index_x);
|
||||
state.updateNegativeFlag(value: state.index_x);
|
||||
}
|
||||
|
||||
static func TAY(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func TAY(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
state.index_y = state.accumulator
|
||||
|
||||
state.updateZeroFlag(value: state.index_y);
|
||||
state.updateNegativeFlag(value: state.index_y);
|
||||
}
|
||||
|
||||
static func TYA(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func TYA(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
state.accumulator = state.index_y
|
||||
|
||||
state.updateZeroFlag(value: state.accumulator);
|
||||
state.updateNegativeFlag(value: state.accumulator);
|
||||
}
|
||||
|
||||
static func DEY(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func DEY(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
state.index_y = state.index_y &- 1
|
||||
|
||||
state.updateZeroFlag(value: state.index_y);
|
||||
state.updateNegativeFlag(value: state.index_y);
|
||||
}
|
||||
|
||||
static func INY(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func INY(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
state.index_y = state.index_y &+ 1
|
||||
|
||||
state.updateZeroFlag(value: state.index_y);
|
||||
state.updateNegativeFlag(value: state.index_y);
|
||||
}
|
||||
|
||||
static func INC(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func INC(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
let address: UInt16 = getOperandAddressForAddressingMode(state: state, mode: addressingMode)
|
||||
var val: UInt8 = state.memoryInterface.readByte(offset: address)
|
||||
|
||||
@ -294,7 +288,7 @@ class Opcodes: NSObject {
|
||||
state.updateNegativeFlag(value: val);
|
||||
}
|
||||
|
||||
static func DEC(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func DEC(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
let address: UInt16 = getOperandAddressForAddressingMode(state: state, mode: addressingMode)
|
||||
var val: UInt8 = state.memoryInterface.readByte(offset: address)
|
||||
|
||||
@ -306,7 +300,7 @@ class Opcodes: NSObject {
|
||||
}
|
||||
|
||||
//CMP
|
||||
static func CMP(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func CMP(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
let mem = getOperandByteForAddressingMode(state: state, mode: addressingMode)
|
||||
let t = state.accumulator &- mem //CMP is a subtract that doesn't affect memory
|
||||
|
||||
@ -315,7 +309,7 @@ class Opcodes: NSObject {
|
||||
state.status_register.carry = (state.accumulator >= mem)
|
||||
}
|
||||
|
||||
static func CPX(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func CPX(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
let mem = getOperandByteForAddressingMode(state: state, mode: addressingMode)
|
||||
let t = state.index_x &- mem //CMP is a subtract that doesn't affect memory
|
||||
|
||||
@ -324,7 +318,7 @@ class Opcodes: NSObject {
|
||||
state.status_register.carry = (state.index_x >= mem)
|
||||
}
|
||||
|
||||
static func CPY(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func CPY(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
let mem = getOperandByteForAddressingMode(state: state, mode: addressingMode)
|
||||
let t = state.index_y &- mem //CMP is a subtract that doesn't affect memory
|
||||
|
||||
@ -334,21 +328,21 @@ class Opcodes: NSObject {
|
||||
}
|
||||
|
||||
//Boolean operators
|
||||
static func EOR(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func EOR(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
state.accumulator = state.accumulator ^ getOperandByteForAddressingMode(state: state, mode: addressingMode)
|
||||
|
||||
state.updateZeroFlag(value: state.accumulator)
|
||||
state.updateNegativeFlag(value: state.accumulator)
|
||||
}
|
||||
|
||||
static func AND(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func AND(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
state.accumulator = state.accumulator & getOperandByteForAddressingMode(state: state, mode: addressingMode)
|
||||
|
||||
state.updateZeroFlag(value: state.accumulator)
|
||||
state.updateNegativeFlag(value: state.accumulator)
|
||||
}
|
||||
|
||||
static func ORA(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func ORA(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
state.accumulator = state.accumulator | getOperandByteForAddressingMode(state: state, mode: addressingMode)
|
||||
|
||||
state.updateZeroFlag(value: state.accumulator)
|
||||
@ -356,7 +350,7 @@ class Opcodes: NSObject {
|
||||
}
|
||||
|
||||
//Bitwise operators
|
||||
static func BIT(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func BIT(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
let operand = getOperandByteForAddressingMode(state: state, mode: addressingMode)
|
||||
let data = state.accumulator & operand
|
||||
|
||||
@ -365,7 +359,7 @@ class Opcodes: NSObject {
|
||||
state.status_register.overflow = (operand & UInt8(0x40)) == 0x40
|
||||
}
|
||||
|
||||
static func ASL(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func ASL(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
let operand: UInt8
|
||||
|
||||
if(addressingMode == .accumulator) {
|
||||
@ -387,7 +381,7 @@ class Opcodes: NSObject {
|
||||
}
|
||||
}
|
||||
|
||||
static func LSR(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func LSR(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
let operand: UInt8
|
||||
|
||||
if(addressingMode == .accumulator) {
|
||||
@ -411,7 +405,7 @@ class Opcodes: NSObject {
|
||||
}
|
||||
}
|
||||
|
||||
static func ROL(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func ROL(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
let operand: UInt8
|
||||
|
||||
if(addressingMode == .accumulator) {
|
||||
@ -440,7 +434,7 @@ class Opcodes: NSObject {
|
||||
}
|
||||
}
|
||||
|
||||
static func ROR(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func ROR(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
let operand: UInt8
|
||||
|
||||
if(addressingMode == .accumulator) {
|
||||
@ -470,51 +464,51 @@ class Opcodes: NSObject {
|
||||
}
|
||||
|
||||
//Processor flag instructions
|
||||
static func CLC(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func CLC(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
state.status_register.carry = false
|
||||
}
|
||||
|
||||
static func SEC(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func SEC(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
state.status_register.carry = true
|
||||
}
|
||||
|
||||
static func CLI(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func CLI(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
state.status_register.irq_disable = false
|
||||
}
|
||||
|
||||
static func SEI(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func SEI(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
state.status_register.irq_disable = true
|
||||
}
|
||||
|
||||
static func CLV(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func CLV(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
state.status_register.overflow = false
|
||||
}
|
||||
|
||||
static func CLD(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func CLD(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
state.status_register.decimal = false
|
||||
}
|
||||
|
||||
static func SED(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func SED(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
state.status_register.decimal = true
|
||||
}
|
||||
|
||||
//Stack instructions
|
||||
static func TXS(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func TXS(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
state.stack_pointer = state.index_x
|
||||
}
|
||||
|
||||
static func TSX(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func TSX(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
state.index_x = state.stack_pointer
|
||||
|
||||
state.updateZeroFlag(value: state.index_x);
|
||||
state.updateNegativeFlag(value: state.index_x);
|
||||
}
|
||||
|
||||
static func PHA(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func PHA(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
state.pushByte(data: state.accumulator)
|
||||
}
|
||||
|
||||
static func PLA(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func PLA(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
state.stack_pointer = state.stack_pointer &+ 1
|
||||
state.accumulator = state.memoryInterface.readByte(offset: state.stackPointerAsUInt16())
|
||||
|
||||
@ -522,7 +516,7 @@ class Opcodes: NSObject {
|
||||
state.updateNegativeFlag(value: state.accumulator);
|
||||
}
|
||||
|
||||
static func PHP(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func PHP(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
var sr = state.status_register
|
||||
sr.brk = true //PHP pushes B as true
|
||||
|
||||
@ -530,81 +524,81 @@ class Opcodes: NSObject {
|
||||
state.stack_pointer = state.stack_pointer &- 1
|
||||
}
|
||||
|
||||
static func PLP(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func PLP(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
state.stack_pointer = state.stack_pointer &+ 1
|
||||
state.status_register.fromByte(state: state.memoryInterface.readByte(offset: state.stackPointerAsUInt16()))
|
||||
state.status_register.brk = false //PLP sets B to 0
|
||||
}
|
||||
|
||||
static func BPL(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func BPL(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
if(!state.status_register.negative) {
|
||||
state.doBranch()
|
||||
}
|
||||
}
|
||||
|
||||
static func BMI(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func BMI(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
if(state.status_register.negative) {
|
||||
state.doBranch()
|
||||
}
|
||||
}
|
||||
|
||||
static func BVC(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func BVC(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
if(!state.status_register.overflow) {
|
||||
state.doBranch()
|
||||
}
|
||||
}
|
||||
|
||||
static func BVS(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func BVS(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
if(state.status_register.overflow) {
|
||||
state.doBranch()
|
||||
}
|
||||
}
|
||||
|
||||
static func BCC(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func BCC(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
if(!state.status_register.carry) {
|
||||
state.doBranch()
|
||||
}
|
||||
}
|
||||
|
||||
static func BCS(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func BCS(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
if(state.status_register.carry) {
|
||||
state.doBranch()
|
||||
}
|
||||
}
|
||||
|
||||
static func BNE(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func BNE(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
if(!state.status_register.zero) {
|
||||
state.doBranch()
|
||||
}
|
||||
}
|
||||
|
||||
static func BEQ(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func BEQ(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
if(state.status_register.zero) {
|
||||
state.doBranch()
|
||||
}
|
||||
}
|
||||
|
||||
//Misc
|
||||
static func JMP(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func JMP(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
state.program_counter = getOperandAddressForAddressingMode(state: state, mode: addressingMode) - 3
|
||||
}
|
||||
|
||||
static func JSR(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func JSR(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
state.pushWord(data: state.program_counter + 2)
|
||||
state.program_counter = state.getOperandWord() - 3
|
||||
}
|
||||
|
||||
static func RTS(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func RTS(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
state.program_counter = state.popWord()
|
||||
}
|
||||
|
||||
static func RTI(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func RTI(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
state.status_register.fromByte(state: state.popByte())
|
||||
state.program_counter = state.popWord() - 1
|
||||
state.status_register.brk = false //RTI sets B to 0
|
||||
}
|
||||
|
||||
static func BRK(state: CPU, addressingMode: AddressingMode) -> Void {
|
||||
static func BRK(state: CPU, addressingMode: CPU.AddressingMode) -> Void {
|
||||
var sr = state.status_register
|
||||
sr.brk = true //BRK pushes B as true
|
||||
state.pushWord(data: state.program_counter + 2)
|
||||
@ -613,5 +607,5 @@ class Opcodes: NSObject {
|
||||
state.program_counter = state.memoryInterface.readWord(offset: 0xFFFE) - 1
|
||||
}
|
||||
|
||||
static func NOP(state: CPU, addressingMode: AddressingMode) -> Void {}
|
||||
static func NOP(state: CPU, addressingMode: CPU.AddressingMode) -> Void {}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user