select disk images to boot
This commit is contained in:
parent
8f9ea69483
commit
1e54fceec3
|
@ -110,11 +110,14 @@ class AppleIIBase: NSObject, EmulatedSystem {
|
||||||
backplane[6] = DiskII(slot: 6, romPath: "/Users/luigi/apple2/341-0027-a.p5")
|
backplane[6] = DiskII(slot: 6, romPath: "/Users/luigi/apple2/341-0027-a.p5")
|
||||||
|
|
||||||
let drive = backplane[6]! as! DiskII
|
let drive = backplane[6]! as! DiskII
|
||||||
//drive.attachDiskImage(imagePath: "/Users/luigi/apple2/Apex II - Apple II Diagnostic (v4.7-1986).DSK")
|
|
||||||
drive.attachDiskImage(imagePath: "/Users/luigi/apple2/clean332sysmas.do")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func doColdReset() {
|
||||||
|
CPU.sharedInstance.coldReset()
|
||||||
|
doReset()
|
||||||
|
}
|
||||||
|
|
||||||
func doReset() {
|
func doReset() {
|
||||||
videoSoftswitches.reset()
|
videoSoftswitches.reset()
|
||||||
videoMode = .Text
|
videoMode = .Text
|
||||||
|
|
|
@ -35,7 +35,7 @@ import Cocoa
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class DiskII: NSObject, Peripheral, HasROM {
|
class DiskII: NSObject, Peripheral, HasROM {
|
||||||
let debug = false
|
let debug = true
|
||||||
|
|
||||||
enum MotorPhase {
|
enum MotorPhase {
|
||||||
case Phase0
|
case Phase0
|
||||||
|
@ -219,17 +219,17 @@ class DiskII: NSObject, Peripheral, HasROM {
|
||||||
let modeString: String
|
let modeString: String
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case 0:
|
case 0:
|
||||||
modeString = "seeking"
|
modeString = "seek"
|
||||||
case 1:
|
case 1:
|
||||||
modeString = "reading"
|
modeString = "read"
|
||||||
case 2:
|
case 2:
|
||||||
modeString = "writing"
|
modeString = "write"
|
||||||
case 4:
|
case 4:
|
||||||
modeString = "formatting"
|
modeString = "format"
|
||||||
default:
|
default:
|
||||||
modeString = "???"
|
modeString = "???"
|
||||||
}
|
}
|
||||||
if(debug) { print("Head is at nibble \(mediaPosition) of track \(currentTrack). DOS is \(modeString) T\(trk) S\(sec).") }
|
if(debug) { print("Head is at nibble \(mediaPosition) of track \(currentTrack). DOS is trying to \(modeString) T\(trk) S\(sec).") }
|
||||||
updateCurrentTrackSectorDisplay(drive: softswitches.DriveSelect, track: currentTrack, sector: Int(sec))
|
updateCurrentTrackSectorDisplay(drive: softswitches.DriveSelect, track: currentTrack, sector: Int(sec))
|
||||||
|
|
||||||
if(softswitches.Q7 == false && byte == nil) {
|
if(softswitches.Q7 == false && byte == nil) {
|
||||||
|
@ -247,10 +247,20 @@ class DiskII: NSObject, Peripheral, HasROM {
|
||||||
case 13:
|
case 13:
|
||||||
//WRITE PROTECT SENSE MODE
|
//WRITE PROTECT SENSE MODE
|
||||||
softswitches.Q6 = true
|
softswitches.Q6 = true
|
||||||
|
if(byte != nil) {
|
||||||
|
preloadedByte = byte!
|
||||||
|
if(debug) { print("WRITE LOAD: shift register contains \(preloadedByte.asHexString())") }
|
||||||
|
}
|
||||||
|
|
||||||
case 14:
|
case 14:
|
||||||
if(debug) { print("Disk II: READ STATUS REGISTER") }
|
if(debug) { print("Disk II: READ STATUS REGISTER") }
|
||||||
softswitches.Q7 = false
|
softswitches.Q7 = false
|
||||||
return 0x00 | (diskImage!.writeProtect ? 0x80 : 0x00) | (softswitches.MotorPowered ? 0x20 : 0x00)
|
if(diskImage != nil) {
|
||||||
|
return 0x00 | (diskImage!.writeProtect ? 0x80 : 0x00) | (softswitches.MotorPowered ? 0x20 : 0x00)
|
||||||
|
} else {
|
||||||
|
return 0x00 | (softswitches.MotorPowered ? 0x20 : 0x00)
|
||||||
|
}
|
||||||
|
|
||||||
case 15:
|
case 15:
|
||||||
softswitches.Q7 = true
|
softswitches.Q7 = true
|
||||||
|
|
||||||
|
@ -323,11 +333,14 @@ class DiskII: NSObject, Peripheral, HasROM {
|
||||||
|
|
||||||
@objc func disableDrive1Motor() {
|
@objc func disableDrive1Motor() {
|
||||||
softswitches.MotorPowered = false
|
softswitches.MotorPowered = false
|
||||||
if(debug) { print("Drive 1 Motor is now off") }
|
if(debug) { print("Drive 1 Motor is now off, saving updated image") }
|
||||||
|
diskImage?.saveDiskImage()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func disableDrive2Motor() {
|
@objc func disableDrive2Motor() {
|
||||||
softswitches.MotorPowered = false
|
softswitches.MotorPowered = false
|
||||||
if(debug) { print("Drive 2 Motor is now off") }
|
if(debug) { print("Drive 2 Motor is now off, saving updated image") }
|
||||||
|
diskImage?.saveDiskImage()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,26 +8,21 @@
|
||||||
|
|
||||||
import Cocoa
|
import Cocoa
|
||||||
|
|
||||||
/* while I figure out this C code port */
|
|
||||||
prefix operator ++
|
|
||||||
postfix operator ++
|
|
||||||
|
|
||||||
// Increment
|
|
||||||
prefix func ++(x: inout Int) -> Int {
|
|
||||||
x += 1
|
|
||||||
return x
|
|
||||||
}
|
|
||||||
|
|
||||||
postfix func ++(x: inout Int) -> Int {
|
|
||||||
x += 1
|
|
||||||
return (x - 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
protocol DiskImageFormat {
|
protocol DiskImageFormat {
|
||||||
static var BYTES_PER_SECTOR: Int { get }
|
static var BYTES_PER_SECTOR: Int { get }
|
||||||
static var SECTORS_PER_TRACK: Int { get }
|
static var SECTORS_PER_TRACK: Int { get }
|
||||||
static var TRACKS_PER_DISK: Int { get }
|
static var TRACKS_PER_DISK: Int { get }
|
||||||
static var BYTES_PER_TRACK: Int { get }
|
static var BYTES_PER_TRACK: Int { get }
|
||||||
|
|
||||||
|
static var SECTOR_ORDER: [Int] { get }
|
||||||
|
|
||||||
|
static func readTrackAndSector(imageData: [UInt8], trackNum: Int, sectorNum: Int) -> [UInt8]
|
||||||
|
}
|
||||||
|
|
||||||
|
enum DiskFormat {
|
||||||
|
case Dos33
|
||||||
|
case Prodos
|
||||||
|
case Raw
|
||||||
}
|
}
|
||||||
|
|
||||||
class Dos33Image: DiskImageFormat {
|
class Dos33Image: DiskImageFormat {
|
||||||
|
@ -37,54 +32,48 @@ class Dos33Image: DiskImageFormat {
|
||||||
static let BYTES_PER_TRACK: Int = BYTES_PER_SECTOR * SECTORS_PER_TRACK
|
static let BYTES_PER_TRACK: Int = BYTES_PER_SECTOR * SECTORS_PER_TRACK
|
||||||
|
|
||||||
//Sectors in a track are in this order.
|
//Sectors in a track are in this order.
|
||||||
// 0 7 14 6 13 5 12 4 11 3 10 2 9 1 8 15
|
static let SECTOR_ORDER = [0, 7, 14, 6, 13, 5, 12, 4, 11, 3, 10, 2, 9, 1, 8, 15]
|
||||||
static let sectorOrder = [0, 7, 14, 6, 13, 5, 12, 4, 11, 3, 10, 2, 9, 1, 8, 15]
|
|
||||||
|
|
||||||
struct VTOC {
|
|
||||||
//http://fileformats.archiveteam.org/wiki/Apple_DOS_file_system
|
|
||||||
|
|
||||||
//$00 unused
|
|
||||||
let catalogTrackNumber = 0 //$01
|
|
||||||
let catalogSectorNumber = 0 //$02
|
|
||||||
let dosInitVersion = 0 //$03
|
|
||||||
//$04-05 unused
|
|
||||||
let volumeNumber = 0 //$06
|
|
||||||
//$07-$26 unused
|
|
||||||
let maxTrackSectorPairs = 0 //$27, should be 122
|
|
||||||
//$28-$2F unused
|
|
||||||
let lastFormattedTrack = 0 //$30
|
|
||||||
let trackDirection = 0 //$31
|
|
||||||
//$32-$33 unused
|
|
||||||
let tracksPerDisk = 0 //$34
|
|
||||||
let sectorsPerTrack = 0 //$35
|
|
||||||
let bytesPerSector = 0 //$36-$37
|
|
||||||
}
|
|
||||||
|
|
||||||
let tableOfContents = VTOC()
|
|
||||||
|
|
||||||
static func readTrackAndSector(imageData: [UInt8], trackNum: Int, sectorNum: Int) -> [UInt8] {
|
static func readTrackAndSector(imageData: [UInt8], trackNum: Int, sectorNum: Int) -> [UInt8] {
|
||||||
//Find the track in our disk.
|
//Find the track in our disk.
|
||||||
let trackOffset = trackNum * Dos33Image.BYTES_PER_TRACK
|
let trackOffset = trackNum * Dos33Image.BYTES_PER_TRACK
|
||||||
//Find the sector in this track.
|
//Find the sector in this track.
|
||||||
let sectorOffset = sectorOrder[sectorNum] * Dos33Image.BYTES_PER_SECTOR
|
let sectorOffset = SECTOR_ORDER[sectorNum] * Dos33Image.BYTES_PER_SECTOR
|
||||||
let offset = trackOffset + sectorOffset
|
let offset = trackOffset + sectorOffset
|
||||||
|
|
||||||
return Array<UInt8>(imageData[offset ..< offset + Dos33Image.BYTES_PER_SECTOR])
|
return Array<UInt8>(imageData[offset ..< offset + Dos33Image.BYTES_PER_SECTOR])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DiskImage: NSObject {
|
class ProdosImage: DiskImageFormat {
|
||||||
enum DiskFormat {
|
static let BYTES_PER_SECTOR: Int = 256
|
||||||
case Dos33
|
static let SECTORS_PER_TRACK: Int = 16
|
||||||
case Prodos
|
static let TRACKS_PER_DISK: Int = 35
|
||||||
case Raw
|
static let BYTES_PER_TRACK: Int = BYTES_PER_SECTOR * SECTORS_PER_TRACK
|
||||||
|
|
||||||
|
//Sectors in a track are in this order.
|
||||||
|
static let SECTOR_ORDER = [0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15]
|
||||||
|
|
||||||
|
static func readTrackAndSector(imageData: [UInt8], trackNum: Int, sectorNum: Int) -> [UInt8] {
|
||||||
|
//Find the track in our disk.
|
||||||
|
let trackOffset = trackNum * BYTES_PER_TRACK
|
||||||
|
//Find the sector in this track.
|
||||||
|
let sectorOffset = SECTOR_ORDER[sectorNum] * BYTES_PER_SECTOR
|
||||||
|
let offset = trackOffset + sectorOffset
|
||||||
|
|
||||||
|
return Array<UInt8>(imageData[offset ..< offset + BYTES_PER_SECTOR])
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DiskImage: NSObject {
|
||||||
|
|
||||||
var encodedTracks = [[UInt8]]()
|
var encodedTracks = [[UInt8]]()
|
||||||
var fileSize: UInt64 = 0
|
var fileSize: UInt64 = 0
|
||||||
var image: DiskImageFormat?
|
var image: DiskImageFormat?
|
||||||
var writeProtect = false
|
var writeProtect = false
|
||||||
|
|
||||||
|
var filename: String
|
||||||
|
|
||||||
init(diskPath: String) {
|
init(diskPath: String) {
|
||||||
do {
|
do {
|
||||||
let attr = try FileManager.default.attributesOfItem(atPath: diskPath)
|
let attr = try FileManager.default.attributesOfItem(atPath: diskPath)
|
||||||
|
@ -93,6 +82,8 @@ class DiskImage: NSObject {
|
||||||
print("Error in DiskImage: \(error)")
|
print("Error in DiskImage: \(error)")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
filename = diskPath
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
var rawData: [UInt8]?
|
var rawData: [UInt8]?
|
||||||
|
|
||||||
|
@ -101,16 +92,39 @@ class DiskImage: NSObject {
|
||||||
print("Couldn't load disk image")
|
print("Couldn't load disk image")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
//Is this a DOS 3.3 format image? Read one sector from track $11.
|
if(filename.contains(".do")) {
|
||||||
let catalogSector: [UInt8] = Dos33Image.readTrackAndSector(imageData: rawData!, trackNum: 0x11, sectorNum: 0)
|
//Is this a DOS 3.3 format image? Read one sector from track $11.
|
||||||
|
image = Dos33Image()
|
||||||
|
let catalogSector: [UInt8] = Dos33Image.readTrackAndSector(imageData: rawData!, trackNum: 0x11, sectorNum: 0)
|
||||||
|
for track in 0..<Dos33Image.TRACKS_PER_DISK {
|
||||||
|
encodedTracks.append(encodeTrack(imageData: rawData!, index: track, volumeNumber: Int(catalogSector[0x06])))
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if(filename.contains(".po")) {
|
||||||
|
/* ProDOS-order image. */
|
||||||
|
image = ProdosImage()
|
||||||
|
|
||||||
|
for track in 0..<ProdosImage.TRACKS_PER_DISK {
|
||||||
|
encodedTracks.append(encodeTrack(imageData: rawData!, index: track, volumeNumber: 0x01))
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* TODO: Hook up logic to figure out the disk format. */
|
||||||
|
image = Dos33Image()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func saveDiskImage() {
|
||||||
|
var diskBytes = [UInt8]()
|
||||||
|
|
||||||
for track in 0..<Dos33Image.TRACKS_PER_DISK {
|
for track in 0 ..< Dos33Image.TRACKS_PER_DISK {
|
||||||
encodedTracks.append(encodeDos33Track(imageData: rawData!, index: track, volumeNumber: Int(catalogSector[0x06])))
|
diskBytes.append(contentsOf: decodeTrack(index: track))
|
||||||
}
|
}
|
||||||
|
|
||||||
let pointer = UnsafeBufferPointer(start:encodedTracks[0], count:encodedTracks[0].count)
|
let ptr = UnsafeBufferPointer(start: diskBytes, count: diskBytes.count)
|
||||||
let data = Data(buffer:pointer)
|
let data = Data(buffer: ptr)
|
||||||
try! data.write(to: URL(fileURLWithPath: "/Users/luigi/apple2/master.dmp"))
|
try! data.write(to: URL(fileURLWithPath: filename + ".modified"))
|
||||||
}
|
}
|
||||||
|
|
||||||
private func loadImageBytes(path: String, size: Int) -> [UInt8]? {
|
private func loadImageBytes(path: String, size: Int) -> [UInt8]? {
|
||||||
|
@ -128,9 +142,36 @@ class DiskImage: NSObject {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
private func encodeDos33Track(imageData: [UInt8], index: Int, volumeNumber: Int) -> [UInt8] {
|
private func decodeTrack(index: Int) -> [UInt8] {
|
||||||
|
/* Find the first sector. Each sector starts with $D5 $AA $AD */
|
||||||
|
let track = encodedTracks[index]
|
||||||
|
var trackBytes = [UInt8]()
|
||||||
|
|
||||||
|
if(image is Dos33Image) {
|
||||||
|
for i in 0 ..< Dos33Image.SECTORS_PER_TRACK {
|
||||||
|
let sectorOffset: Int = 0x47 + (0x18C * Dos33Image.SECTOR_ORDER.index(of: i)!)
|
||||||
|
let nibbles: [UInt8] = [UInt8](track[sectorOffset ... sectorOffset + 343])
|
||||||
|
trackBytes.append(contentsOf: DecodeSectorSixAndTwo(nibbles: nibbles))
|
||||||
|
}
|
||||||
|
} else if(image is ProdosImage) {
|
||||||
|
for i in 0 ..< ProdosImage.SECTORS_PER_TRACK {
|
||||||
|
let sectorOffset: Int = 0x47 + (0x18C * ProdosImage.SECTOR_ORDER.index(of: i)!)
|
||||||
|
let nibbles: [UInt8] = [UInt8](track[sectorOffset ... sectorOffset + 343])
|
||||||
|
trackBytes.append(contentsOf: DecodeSectorSixAndTwo(nibbles: nibbles))
|
||||||
|
}
|
||||||
|
} else if(image != nil) {
|
||||||
|
for i in 0 ..< Dos33Image.SECTORS_PER_TRACK {
|
||||||
|
let sectorOffset: Int = 0x47 + (0x18C * i) /* If we don't recognize the format, just use a sequential sector order. */
|
||||||
|
let nibbles: [UInt8] = [UInt8](track[sectorOffset ... sectorOffset + 343])
|
||||||
|
trackBytes.append(contentsOf: DecodeSectorSixAndTwo(nibbles: nibbles))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return trackBytes
|
||||||
|
}
|
||||||
|
|
||||||
|
private func encodeTrack(imageData: [UInt8], index: Int, volumeNumber: Int) -> [UInt8] {
|
||||||
var encodedData = [UInt8]()
|
var encodedData = [UInt8]()
|
||||||
let dataOffset = index * Dos33Image.BYTES_PER_TRACK
|
|
||||||
|
|
||||||
//Prologue: add 48 self-syncing bytes
|
//Prologue: add 48 self-syncing bytes
|
||||||
for _ in 1..<0x31 { encodedData.append(selfSync) }
|
for _ in 1..<0x31 { encodedData.append(selfSync) }
|
||||||
|
@ -190,6 +231,37 @@ class DiskImage: NSObject {
|
||||||
return writtenData
|
return writtenData
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func DecodeSectorSixAndTwo(nibbles: [UInt8]) -> [UInt8] {
|
||||||
|
var sector = [UInt8](repeating: 0x00, count: 256)
|
||||||
|
var readBuffer = [UInt8](repeating: 0x00, count: 343)
|
||||||
|
|
||||||
|
readBuffer[0x155] = SixAndTwoDecode(byte: nibbles[0]) ^ 0
|
||||||
|
|
||||||
|
for i in 1 ... 85 {
|
||||||
|
readBuffer[0x155 - i] = SixAndTwoDecode(byte: nibbles[i]) ^ readBuffer[0x156 - i]
|
||||||
|
}
|
||||||
|
|
||||||
|
readBuffer[0x000] = SixAndTwoDecode(byte: nibbles[86]) ^ readBuffer[0x100]
|
||||||
|
|
||||||
|
for i in 87 ... 341 {
|
||||||
|
readBuffer[i - 86] = SixAndTwoDecode(byte: nibbles[i]) ^ readBuffer[i - 87]
|
||||||
|
}
|
||||||
|
|
||||||
|
var secondaryShift = 0
|
||||||
|
for i in 0 ... 255 {
|
||||||
|
let secondaryOffset = 0x100 + (0x55 - (i % 0x56))
|
||||||
|
|
||||||
|
sector[i] |= readBuffer[i] << 2
|
||||||
|
sector[i] |= GetSwappedLowBits(byte: readBuffer[secondaryOffset] >> secondaryShift)
|
||||||
|
|
||||||
|
if(secondaryOffset == 0x100) {
|
||||||
|
secondaryShift += 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sector
|
||||||
|
}
|
||||||
|
|
||||||
private func GetSwappedLowBits(byte: UInt8) -> UInt8 {
|
private func GetSwappedLowBits(byte: UInt8) -> UInt8 {
|
||||||
let b0 = byte & 0b00000001
|
let b0 = byte & 0b00000001
|
||||||
let b1 = byte & 0b00000010
|
let b1 = byte & 0b00000010
|
||||||
|
@ -235,6 +307,10 @@ class DiskImage: NSObject {
|
||||||
return SixAndTwoTranslationTable[Int(byte)]
|
return SixAndTwoTranslationTable[Int(byte)]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SixAndTwoDecode(byte: UInt8) -> UInt8 {
|
||||||
|
return UInt8(SixAndTwoTranslationTable.index(of: byte)!)
|
||||||
|
}
|
||||||
|
|
||||||
//A group of self-syncing bytes. This pattern can be repeated as long as required.
|
//A group of self-syncing bytes. This pattern can be repeated as long as required.
|
||||||
//let selfSyncFive: [UInt8] = [0b11111111, 0b00111111, 0b11001111, 0b11110011, 0b11111100]
|
//let selfSyncFive: [UInt8] = [0b11111111, 0b00111111, 0b11001111, 0b11110011, 0b11111100]
|
||||||
private let selfSync: UInt8 = 0xFF
|
private let selfSync: UInt8 = 0xFF
|
||||||
|
|
|
@ -64,6 +64,25 @@ class AppleIIViewController: NSViewController {
|
||||||
EmulatedSystemInstance!.doReset()
|
EmulatedSystemInstance!.doReset()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@IBAction func doColdReset(_ sender: Any) {
|
||||||
|
EmulatedSystemInstance!.doColdReset()
|
||||||
|
}
|
||||||
|
|
||||||
|
@IBAction func insertDiskIntoDrive1(_ sender: Any) {
|
||||||
|
let picker = NSOpenPanel()
|
||||||
|
|
||||||
|
picker.title = "Select a 5.25\" disk image"
|
||||||
|
picker.showsHiddenFiles = false
|
||||||
|
picker.canChooseFiles = true
|
||||||
|
picker.canChooseDirectories = false
|
||||||
|
picker.allowsMultipleSelection = false
|
||||||
|
picker.allowedFileTypes = ["do", "po"]
|
||||||
|
|
||||||
|
if(picker.runModal() == .OK) {
|
||||||
|
(EmulatedSystemInstance!.backplane[6] as! DiskII).attachDiskImage(imagePath: picker.url!.path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override func keyDown(with event: NSEvent) {
|
override func keyDown(with event: NSEvent) {
|
||||||
let leftArrowKeyCode = 123
|
let leftArrowKeyCode = 123
|
||||||
let rightArrowKeyCode = 124
|
let rightArrowKeyCode = 124
|
||||||
|
|
|
@ -64,13 +64,20 @@
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
<menu key="submenu" title="File" id="bib-Uj-vzu">
|
<menu key="submenu" title="File" id="bib-Uj-vzu">
|
||||||
<items>
|
<items>
|
||||||
<menuItem title="Insert Disk into Drive 0..." id="IYa-pn-S38">
|
<menuItem title="Insert Disk into Drive 1..." keyEquivalent="1" id="IYa-pn-S38">
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
<connections>
|
||||||
|
<action selector="insertDiskIntoDrive1:" target="Ady-hI-5gd" id="3Gf-TM-cb6"/>
|
||||||
|
</connections>
|
||||||
</menuItem>
|
</menuItem>
|
||||||
<menuItem title="Insert Disk into Drive 1..." id="Gdi-Dy-E1U">
|
<menuItem title="Insert Disk into Drive 2..." keyEquivalent="2" id="Gdi-Dy-E1U"/>
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
<menuItem isSeparatorItem="YES" id="YNZ-dh-D7s"/>
|
||||||
|
<menuItem title="Cold Reset" keyEquivalent="r" id="PoX-c5-5zb">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="doColdReset:" target="Ady-hI-5gd" id="mCR-M2-XLp"/>
|
||||||
|
</connections>
|
||||||
</menuItem>
|
</menuItem>
|
||||||
<menuItem title="Reset" keyEquivalent="r" id="aTl-1u-JFS">
|
<menuItem title="Warm Reset" keyEquivalent="r" id="aTl-1u-JFS">
|
||||||
<connections>
|
<connections>
|
||||||
<action selector="doReset:" target="Ady-hI-5gd" id="7dg-B5-6Ok"/>
|
<action selector="doReset:" target="Ady-hI-5gd" id="7dg-B5-6Ok"/>
|
||||||
</connections>
|
</connections>
|
||||||
|
@ -214,7 +221,7 @@
|
||||||
</viewController>
|
</viewController>
|
||||||
<customObject id="o4k-Ip-qpX" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
<customObject id="o4k-Ip-qpX" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||||
</objects>
|
</objects>
|
||||||
<point key="canvasLocation" x="105" y="-91"/>
|
<point key="canvasLocation" x="97" y="-88"/>
|
||||||
</scene>
|
</scene>
|
||||||
</scenes>
|
</scenes>
|
||||||
</document>
|
</document>
|
||||||
|
|
|
@ -179,6 +179,28 @@ final class CPU: NSObject {
|
||||||
breakpoints = [UInt16]()
|
breakpoints = [UInt16]()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func coldReset() {
|
||||||
|
instruction_register = 0
|
||||||
|
|
||||||
|
accumulator = 0
|
||||||
|
index_x = 0
|
||||||
|
index_y = 0
|
||||||
|
stack_pointer = 0
|
||||||
|
program_counter = 0
|
||||||
|
status_register = StatusRegister(negative: false, overflow: false, brk: false, decimal: false, irq_disable: false, zero: false, carry: false)
|
||||||
|
|
||||||
|
//Some instructions incur a 1-cycle penalty if crossing a page boundary.
|
||||||
|
page_boundary_crossed = false
|
||||||
|
//Branches incur a 1-cycle penalty if taken plus the page boundary penalty if necessary.
|
||||||
|
branch_was_taken = false
|
||||||
|
|
||||||
|
performReset()
|
||||||
|
|
||||||
|
for address in 0 ..< 0xC000 {
|
||||||
|
memoryInterface.writeByte(offset: UInt16(address), value: 0x00, bypassOverrides: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func getOperandByte() -> UInt8 {
|
func getOperandByte() -> UInt8 {
|
||||||
//Returns the operand byte after the current instruction byte.
|
//Returns the operand byte after the current instruction byte.
|
||||||
return memoryInterface.readByte(offset: program_counter + 1)
|
return memoryInterface.readByte(offset: program_counter + 1)
|
||||||
|
|
Loading…
Reference in New Issue