2019-07-25 22:51:36 -07:00
|
|
|
|
//
|
|
|
|
|
// ViewController.swift
|
2020-07-13 10:23:33 -07:00
|
|
|
|
// Steve ][
|
2019-07-25 22:51:36 -07:00
|
|
|
|
//
|
|
|
|
|
// Created by Tamas Rudnai on 7/25/19.
|
2020-07-13 10:16:37 -07:00
|
|
|
|
// Copyright © 2019, 2020 Tamas Rudnai. All rights reserved.
|
2020-07-13 10:10:33 -07:00
|
|
|
|
//
|
|
|
|
|
// This file is part of Steve ][ -- The Apple ][ Emulator.
|
|
|
|
|
//
|
|
|
|
|
// Steve ][ is free software: you can redistribute it and/or modify
|
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
// (at your option) any later version.
|
|
|
|
|
//
|
|
|
|
|
// Steve ][ is distributed in the hope that it will be useful,
|
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
|
//
|
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
|
// along with Steve ][. If not, see <https://www.gnu.org/licenses/>.
|
2019-07-25 22:51:36 -07:00
|
|
|
|
//
|
|
|
|
|
|
2020-01-27 22:54:03 -08:00
|
|
|
|
|
2019-07-25 22:51:36 -07:00
|
|
|
|
import Cocoa
|
2020-02-07 00:40:31 -08:00
|
|
|
|
import AVFoundation
|
|
|
|
|
|
2019-07-25 22:51:36 -07:00
|
|
|
|
|
2020-01-27 22:54:03 -08:00
|
|
|
|
let K : Double = 1000.0
|
|
|
|
|
let M : Double = (K * K)
|
|
|
|
|
let G : Double = (M * K)
|
|
|
|
|
let T : Double = (G * K)
|
|
|
|
|
|
|
|
|
|
let KB : Double = 1024.0
|
|
|
|
|
let MB : Double = (KB * KB)
|
|
|
|
|
let GB : Double = (MB * KB)
|
|
|
|
|
let TB : Double = (GB * KB)
|
|
|
|
|
|
|
|
|
|
|
2020-06-20 22:14:39 -07:00
|
|
|
|
let colorWhite = NSColor.init( red:0.9296875, green:0.9296875, blue:0.9296875, alpha: 1 )
|
|
|
|
|
let colorGreen = NSColor.init( red:0.16796875, green:0.84375, blue:0.2890625, alpha: 1 )
|
|
|
|
|
let colorOrange = NSColor.init( red:1, green:0.38671875, blue:0.0078125, alpha: 1 )
|
|
|
|
|
|
|
|
|
|
var monoColor = colorGreen;
|
|
|
|
|
|
2020-02-07 00:40:31 -08:00
|
|
|
|
var spk_up: AVAudioPlayer?
|
|
|
|
|
var spk_dn: AVAudioPlayer?
|
|
|
|
|
|
|
|
|
|
@_cdecl("ViewController_spk_up_play")
|
|
|
|
|
func spk_up_play() {
|
|
|
|
|
spk_up?.stop()
|
|
|
|
|
spk_dn?.stop()
|
|
|
|
|
spk_up?.play()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@_cdecl("ViewController_spk_dn_play")
|
|
|
|
|
func spk_dn_play() {
|
|
|
|
|
spk_up?.stop()
|
|
|
|
|
spk_dn?.stop()
|
|
|
|
|
spk_dn?.play()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2020-06-24 15:44:15 -07:00
|
|
|
|
//#if METAL_YES
|
|
|
|
|
//import Metal
|
|
|
|
|
//#endif
|
2019-11-27 20:27:32 -08:00
|
|
|
|
|
2020-04-27 07:26:04 -07:00
|
|
|
|
class ViewController: NSViewController {
|
2019-07-25 22:51:36 -07:00
|
|
|
|
|
2019-09-19 02:27:56 -07:00
|
|
|
|
@IBOutlet weak var displayField: NSTextField!
|
2019-07-30 01:05:21 -07:00
|
|
|
|
@IBOutlet weak var display: NSTextFieldCell!
|
2019-09-17 02:12:05 -07:00
|
|
|
|
@IBOutlet weak var speedometer: NSTextFieldCell!
|
2020-05-29 08:50:47 -07:00
|
|
|
|
@IBOutlet weak var lores: LoRes!
|
2019-11-27 20:27:32 -08:00
|
|
|
|
@IBOutlet weak var hires: HiRes!
|
2020-06-10 19:11:27 -07:00
|
|
|
|
@IBOutlet weak var splashScreen: NSView!
|
2020-06-17 09:46:17 -07:00
|
|
|
|
@IBOutlet weak var scanLines: NSImageView!
|
2019-11-27 20:27:32 -08:00
|
|
|
|
|
2020-06-17 09:46:17 -07:00
|
|
|
|
var CRTMonitor = false
|
2020-06-20 18:46:26 -07:00
|
|
|
|
var ColorMonitor = true
|
2020-06-02 10:10:18 -07:00
|
|
|
|
var Keyboard2Joystick = true
|
|
|
|
|
var Mouse2Joystick = false
|
|
|
|
|
var MouseInterface = true
|
|
|
|
|
|
2019-09-17 02:12:05 -07:00
|
|
|
|
|
2019-09-10 00:00:00 -07:00
|
|
|
|
// static let charConvStr : String =
|
|
|
|
|
// "@🄰🄱🄲🄳🄴🄵🄶🄷🄸🄹🄺🄻🄼🄽🄾🄿🅀🅁🅂🅃🅄🅅🅆🅇🅈🅉[\\]^_ !\"#$%&'()*+,-./0123456789:;<=>?" +
|
|
|
|
|
// "@🅰🅱🅲🅳🅴🅵🅶🅷🅸🅹🅺🅻🅼🅽🅾🅿🆀🆁🆂🆃🆄🆅🆆🆇🆈🆉[\\]^_⬛︎!\"#$%&'()*+,-./0123456789:;<=>?" + // FL
|
|
|
|
|
// "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_ !\"#$%&'()*+,-./0123456789:;<=>?" +
|
|
|
|
|
// "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~?"
|
|
|
|
|
|
2019-09-19 02:27:56 -07:00
|
|
|
|
// static let charConvStr : String =
|
|
|
|
|
// "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_ !\"#$%&'()*+,-./0123456789:;<=>?" +
|
|
|
|
|
// "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_░!\"#$%&'()*+,-./0123456789:;<=>?" + // FL
|
|
|
|
|
// "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_\u{E0A0}!\"#$%&'()*+,-./0123456789:;<=>?" +
|
|
|
|
|
// "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~?"
|
|
|
|
|
|
|
|
|
|
// static let charConvStr : String =
|
|
|
|
|
// "\u{E140}\u{E141}\u{E142}\u{E143}\u{E144}\u{E145}\u{E146}\u{E147}\u{E148}\u{E149}\u{E14A}\u{E14B}\u{E14C}\u{E14D}\u{E14E}\u{E14F}\u{E150}\u{E151}\u{E152}\u{E153}\u{E154}\u{E155}\u{E156}\u{E157}\u{E158}\u{E159}\u{E15A}\u{E15B}\u{E15C}\u{E15D}\u{E15E}\u{E15F}\u{E120}\u{E121}\u{E122}\u{E123}\u{E124}\u{E125}\u{E126}\u{E127}\u{E128}\u{E129}\u{E12A}\u{E12B}\u{E12C}\u{E12D}\u{E12E}\u{E12F}\u{E130}\u{E131}\u{E132}\u{E133}\u{E134}\u{E135}\u{E136}\u{E137}\u{E138}\u{E139}\u{E13A}\u{E13B}\u{E13C}\u{E13D}\u{E13E}\u{E13F}" +
|
|
|
|
|
// "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_░!\"#$%&'()*+,-./0123456789:;<=>?" + // FL
|
|
|
|
|
// "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_\u{E0A0}!\"#$%&'()*+,-./0123456789:;<=>?" +
|
|
|
|
|
// "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~?"
|
2019-09-08 19:55:19 -07:00
|
|
|
|
|
2019-09-19 02:27:56 -07:00
|
|
|
|
static let charConvStrFlashOff : String =
|
|
|
|
|
"\u{E140}\u{E141}\u{E142}\u{E143}\u{E144}\u{E145}\u{E146}\u{E147}\u{E148}\u{E149}\u{E14A}\u{E14B}\u{E14C}\u{E14D}\u{E14E}\u{E14F}\u{E150}\u{E151}\u{E152}\u{E153}\u{E154}\u{E155}\u{E156}\u{E157}\u{E158}\u{E159}\u{E15A}\u{E15B}\u{E15C}\u{E15D}\u{E15E}\u{E15F}\u{E120}\u{E121}\u{E122}\u{E123}\u{E124}\u{E125}\u{E126}\u{E127}\u{E128}\u{E129}\u{E12A}\u{E12B}\u{E12C}\u{E12D}\u{E12E}\u{E12F}\u{E130}\u{E131}\u{E132}\u{E133}\u{E134}\u{E135}\u{E136}\u{E137}\u{E138}\u{E139}\u{E13A}\u{E13B}\u{E13C}\u{E13D}\u{E13E}\u{E13F}" +
|
2020-04-25 21:28:18 -07:00
|
|
|
|
|
2019-09-19 02:27:56 -07:00
|
|
|
|
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_ !\"#$%&'()*+,-./0123456789:;<=>?" + // FL
|
2020-04-25 21:28:18 -07:00
|
|
|
|
|
2019-09-22 01:31:09 -07:00
|
|
|
|
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_ !\"#$%&'()*+,-./0123456789:;<=>?" +
|
2020-04-25 21:28:18 -07:00
|
|
|
|
|
2020-07-01 17:47:43 -07:00
|
|
|
|
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u{E27F}"
|
2019-09-19 02:27:56 -07:00
|
|
|
|
|
|
|
|
|
static let charConvStrFlashOn : String =
|
|
|
|
|
"\u{E140}\u{E141}\u{E142}\u{E143}\u{E144}\u{E145}\u{E146}\u{E147}\u{E148}\u{E149}\u{E14A}\u{E14B}\u{E14C}\u{E14D}\u{E14E}\u{E14F}\u{E150}\u{E151}\u{E152}\u{E153}\u{E154}\u{E155}\u{E156}\u{E157}\u{E158}\u{E159}\u{E15A}\u{E15B}\u{E15C}\u{E15D}\u{E15E}\u{E15F}\u{E120}\u{E121}\u{E122}\u{E123}\u{E124}\u{E125}\u{E126}\u{E127}\u{E128}\u{E129}\u{E12A}\u{E12B}\u{E12C}\u{E12D}\u{E12E}\u{E12F}\u{E130}\u{E131}\u{E132}\u{E133}\u{E134}\u{E135}\u{E136}\u{E137}\u{E138}\u{E139}\u{E13A}\u{E13B}\u{E13C}\u{E13D}\u{E13E}\u{E13F}" +
|
|
|
|
|
"\u{E140}\u{E141}\u{E142}\u{E143}\u{E144}\u{E145}\u{E146}\u{E147}\u{E148}\u{E149}\u{E14A}\u{E14B}\u{E14C}\u{E14D}\u{E14E}\u{E14F}\u{E150}\u{E151}\u{E152}\u{E153}\u{E154}\u{E155}\u{E156}\u{E157}\u{E158}\u{E159}\u{E15A}\u{E15B}\u{E15C}\u{E15D}\u{E15E}\u{E15F}\u{E120}\u{E121}\u{E122}\u{E123}\u{E124}\u{E125}\u{E126}\u{E127}\u{E128}\u{E129}\u{E12A}\u{E12B}\u{E12C}\u{E12D}\u{E12E}\u{E12F}\u{E130}\u{E131}\u{E132}\u{E133}\u{E134}\u{E135}\u{E136}\u{E137}\u{E138}\u{E139}\u{E13A}\u{E13B}\u{E13C}\u{E13D}\u{E13E}\u{E13F}" +
|
2020-04-25 21:28:18 -07:00
|
|
|
|
|
2019-09-22 01:31:09 -07:00
|
|
|
|
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_ !\"#$%&'()*+,-./0123456789:;<=>?" +
|
2020-04-25 21:28:18 -07:00
|
|
|
|
|
2020-07-01 17:47:43 -07:00
|
|
|
|
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u{E27F}"
|
2019-09-19 02:27:56 -07:00
|
|
|
|
|
2019-09-22 01:31:09 -07:00
|
|
|
|
static let charConvTblFlashOn = Array( charConvStrFlashOn )
|
|
|
|
|
static let charConvTblFlashOff = Array( charConvStrFlashOff )
|
|
|
|
|
|
|
|
|
|
static var charConvTbl = charConvTblFlashOn
|
2020-04-26 00:23:05 -07:00
|
|
|
|
|
2020-06-06 13:19:29 -07:00
|
|
|
|
static var romFileName = "Apple2e_Enhanced.rom";
|
2019-09-08 19:55:19 -07:00
|
|
|
|
|
2020-05-29 08:50:47 -07:00
|
|
|
|
static let textLineOfs : [Int] = [
|
2019-09-08 19:55:19 -07:00
|
|
|
|
0x000, 0x080, 0x100, 0x180, 0x200, 0x280, 0x300, 0x380, 0x028, 0x0A8, 0x128, 0x1A8,
|
|
|
|
|
0x228, 0x2A8, 0x328, 0x3A8, 0x050, 0x0D0, 0x150, 0x1D0, 0x250, 0x2D0, 0x350, 0x3D0
|
|
|
|
|
]
|
|
|
|
|
|
2020-06-04 11:37:35 -07:00
|
|
|
|
|
|
|
|
|
func dialogOK(title: String, text: String) {
|
|
|
|
|
let alert = NSAlert()
|
|
|
|
|
alert.messageText = title
|
|
|
|
|
alert.informativeText = text
|
|
|
|
|
alert.alertStyle = .warning
|
|
|
|
|
alert.addButton(withTitle: "OK")
|
|
|
|
|
alert.runModal()
|
|
|
|
|
// return alert.runModal() == .alertFirstButtonReturn
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@objc func chk_woz_load(err : Int32) {
|
|
|
|
|
switch (err) {
|
|
|
|
|
case WOZ_ERR_OK:
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
case WOZ_ERR_FILE_NOT_FOUND:
|
|
|
|
|
dialogOK(title: "Error Loading Disk Image", text: "File Not Found!")
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
case WOZ_ERR_NOT_WOZ_FILE:
|
|
|
|
|
dialogOK(title: "Error Loading Disk Image", text: "File is not a WOZ image!")
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
case WOZ_ERR_BAD_CHUNK_HDR, WOZ_ERR_BAD_DATA:
|
|
|
|
|
dialogOK(title: "Error Loading Disk Image", text: "Malformed WOZ image!")
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
dialogOK(title: "Error Loading Disk Image", text: "Unknown Error! (\(err))" )
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2019-09-11 18:36:30 -07:00
|
|
|
|
var workItem : DispatchWorkItem? = nil;
|
2020-06-25 20:23:08 -07:00
|
|
|
|
@IBAction func PowerOn(_ sender: Any) {
|
2020-05-09 14:40:42 -07:00
|
|
|
|
|
|
|
|
|
upd.suspend()
|
2020-06-17 09:46:17 -07:00
|
|
|
|
cpuState = cpuState_inited;
|
2020-06-25 20:23:08 -07:00
|
|
|
|
spkr_stopAll()
|
2020-05-09 03:39:55 -07:00
|
|
|
|
|
|
|
|
|
//------------------------------------------------------------
|
|
|
|
|
// Animated Splash Screen fade out and (Text) Monitor fade in
|
|
|
|
|
|
2020-05-09 14:40:42 -07:00
|
|
|
|
hires.isHidden = true
|
2020-05-09 03:39:55 -07:00
|
|
|
|
displayField.alphaValue = 0
|
|
|
|
|
displayField.isHidden = false
|
|
|
|
|
splashScreen.alphaValue = 1
|
|
|
|
|
splashScreen.isHidden = false
|
|
|
|
|
|
2020-05-09 14:40:42 -07:00
|
|
|
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
2020-05-09 03:39:55 -07:00
|
|
|
|
NSAnimationContext.runAnimationGroup({ (context) in
|
2020-05-09 14:40:42 -07:00
|
|
|
|
context.duration = 0.5
|
2020-05-09 03:39:55 -07:00
|
|
|
|
// Use the value you want to animate to (NOT the starting value)
|
|
|
|
|
self.displayField.animator().alphaValue = 1
|
|
|
|
|
self.splashScreen.animator().alphaValue = 0
|
|
|
|
|
},
|
|
|
|
|
completionHandler:{ () -> Void in
|
|
|
|
|
self.displayField.alphaValue = 1
|
|
|
|
|
self.splashScreen.isHidden = true
|
|
|
|
|
})
|
2020-05-09 14:40:42 -07:00
|
|
|
|
|
2020-06-24 15:44:15 -07:00
|
|
|
|
m6502_ColdReset( Bundle.main.resourcePath! + "/rom/", ViewController.romFileName )
|
2020-05-09 14:40:42 -07:00
|
|
|
|
|
2020-06-17 09:46:17 -07:00
|
|
|
|
cpuState = cpuState_running;
|
2020-05-09 14:40:42 -07:00
|
|
|
|
self.upd.resume()
|
2020-05-09 03:39:55 -07:00
|
|
|
|
}
|
|
|
|
|
//------------------------------------------------------------
|
2020-02-07 00:40:31 -08:00
|
|
|
|
|
2019-09-19 02:27:56 -07:00
|
|
|
|
#if SPEEDTEST
|
|
|
|
|
if ( workItem != nil ) {
|
|
|
|
|
workItem!.cancel();
|
|
|
|
|
workItem = nil;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
workItem = DispatchWorkItem {
|
|
|
|
|
DispatchQueue.global(qos: .userInteractive).async {
|
|
|
|
|
// DispatchQueue.global(qos: .userInitiated).async {
|
|
|
|
|
// DispatchQueue.global(qos: .background).async {
|
|
|
|
|
tst6502()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
DispatchQueue.global().async(execute: workItem!);
|
|
|
|
|
}
|
|
|
|
|
#else
|
2020-04-30 07:26:46 -07:00
|
|
|
|
|
2020-05-09 14:40:42 -07:00
|
|
|
|
|
2019-09-19 02:27:56 -07:00
|
|
|
|
#endif
|
2019-09-09 00:27:31 -07:00
|
|
|
|
}
|
2020-06-25 20:23:08 -07:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@IBAction func PowerOff(_ sender: Any) {
|
|
|
|
|
|
|
|
|
|
upd.suspend()
|
|
|
|
|
cpuState = cpuState_inited;
|
|
|
|
|
spkr_stopAll()
|
|
|
|
|
|
|
|
|
|
//------------------------------------------------------------
|
|
|
|
|
// Animated Splash Screen fade out and (Text) Monitor fade in
|
|
|
|
|
|
|
|
|
|
hires.isHidden = true
|
|
|
|
|
displayField.alphaValue = 0
|
|
|
|
|
displayField.isHidden = false
|
|
|
|
|
splashScreen.alphaValue = 1
|
|
|
|
|
splashScreen.isHidden = false
|
|
|
|
|
|
|
|
|
|
//------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@IBAction func Pause(_ sender: Any) {
|
|
|
|
|
|
|
|
|
|
switch ( cpuState ) {
|
|
|
|
|
case cpuState_halted:
|
|
|
|
|
upd.resume()
|
|
|
|
|
cpuState = cpuState_running
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
case cpuState_running:
|
|
|
|
|
upd.suspend()
|
|
|
|
|
cpuState = cpuState_halted
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
// upd.suspend()
|
|
|
|
|
// cpuState = cpuState_halted
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-09 00:27:31 -07:00
|
|
|
|
|
|
|
|
|
@IBAction func Reset(_ sender: Any) {
|
2020-05-02 22:39:54 -07:00
|
|
|
|
// m6502.interrupt = SOFTRESET;
|
2020-05-02 22:35:59 -07:00
|
|
|
|
|
2020-05-02 22:39:54 -07:00
|
|
|
|
// let saved_frm_set = clk_6502_per_frm_set;
|
|
|
|
|
// clk_6502_per_frm_set = 0
|
|
|
|
|
// clk_6502_per_frm_max = 0
|
|
|
|
|
// // wait for 1 ms to allow the simulation to halt
|
|
|
|
|
// usleep(10000);
|
2020-05-02 22:35:59 -07:00
|
|
|
|
|
|
|
|
|
softReset()
|
|
|
|
|
|
2020-05-02 22:39:54 -07:00
|
|
|
|
// clk_6502_per_frm_set = saved_frm_set
|
2019-09-09 00:27:31 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2020-05-24 21:04:34 -07:00
|
|
|
|
static let textPage1Addr = 0x400
|
|
|
|
|
static let textPage2Addr = 0x800
|
2020-02-22 16:37:54 -08:00
|
|
|
|
static let textBufferSize = 0x400
|
2020-04-27 07:26:04 -07:00
|
|
|
|
|
|
|
|
|
// static only needed to be able to initialize things
|
|
|
|
|
static let textLines = 24
|
|
|
|
|
static let textCols = 40
|
|
|
|
|
static let lineEndChars = 1
|
|
|
|
|
|
|
|
|
|
// these are needed to be able to easy access to these constants from instances
|
|
|
|
|
let textLines = ViewController.textLines
|
|
|
|
|
let textCols = ViewController.textCols
|
|
|
|
|
let lineEndChars = ViewController.lineEndChars
|
|
|
|
|
|
2020-02-22 16:37:54 -08:00
|
|
|
|
var frameCnt = 0
|
|
|
|
|
// let spaceChar : Character = "\u{E17F}"
|
|
|
|
|
// let blockChar : Character = "\u{E07F}"
|
2020-04-27 07:26:04 -07:00
|
|
|
|
// static let spaceChar : Character = " "
|
|
|
|
|
// static let blockChar : Character = "░"
|
|
|
|
|
// static var flashingSpace : Character = " "
|
2020-02-22 16:37:54 -08:00
|
|
|
|
|
2020-05-01 14:43:41 -07:00
|
|
|
|
let ramBufferPointer = UnsafeRawBufferPointer(start: MEM, count: 64 * 1024)
|
2020-05-26 21:13:31 -07:00
|
|
|
|
static let textPage1Pointer = UnsafeRawBufferPointer(start: MEM + textPage1Addr, count: textBufferSize)
|
|
|
|
|
static let textPage2Pointer = UnsafeRawBufferPointer(start: MEM + textPage2Addr, count: textBufferSize)
|
|
|
|
|
static let textIntBufferPointer = UnsafeRawBufferPointer(start: RAM + textPage1Addr, count: textBufferSize)
|
|
|
|
|
static let textAuxBufferPointer = UnsafeRawBufferPointer(start: AUX + textPage1Addr, count: textBufferSize)
|
|
|
|
|
|
2020-05-29 08:50:47 -07:00
|
|
|
|
// TODO: Render text screen in native C
|
|
|
|
|
// static let textScreen = UnsafeMutableRawPointer(mutating: testText)
|
|
|
|
|
|
|
|
|
|
|
2020-05-24 21:04:34 -07:00
|
|
|
|
var textBufferPointer = textPage1Pointer
|
2020-04-27 07:26:04 -07:00
|
|
|
|
|
|
|
|
|
static let textArraySize = textLines * (textCols + lineEndChars) + textCols * 2
|
|
|
|
|
|
|
|
|
|
var txtClear = [Character](repeating: " ", count: textArraySize * 2)
|
|
|
|
|
var txtArr = [Character](repeating: " ", count: textArraySize * 2)
|
2020-02-22 16:37:54 -08:00
|
|
|
|
|
|
|
|
|
var s = String()
|
|
|
|
|
|
|
|
|
|
func HexDump() {
|
|
|
|
|
var txt : String = ""
|
|
|
|
|
|
|
|
|
|
for y in 0...textLines - 1 {
|
|
|
|
|
txt += String(format: "%04X: ", y * 16)
|
|
|
|
|
for x in 0...15 {
|
|
|
|
|
let byte = ramBufferPointer[ y * 16 + x ]
|
|
|
|
|
let chr = String(format: "%02X ", byte)
|
|
|
|
|
txt += chr
|
|
|
|
|
}
|
|
|
|
|
txt += "\n"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DispatchQueue.main.async {
|
|
|
|
|
self.display.stringValue = txt
|
|
|
|
|
self.speedometer.stringValue = String(format: "%0.3lf MHz", mhz);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2019-09-22 01:31:09 -07:00
|
|
|
|
// AppleScript Keycodes
|
|
|
|
|
let leftArrowKey = 123
|
|
|
|
|
let rightArrowKey = 124
|
|
|
|
|
let upArrowKey = 126
|
|
|
|
|
let downArrowKey = 125
|
2020-02-22 16:37:54 -08:00
|
|
|
|
|
|
|
|
|
var ddd = 9;
|
2019-09-22 01:31:09 -07:00
|
|
|
|
|
2020-04-27 07:26:04 -07:00
|
|
|
|
override var acceptsFirstResponder: Bool {
|
2020-07-11 13:16:10 -07:00
|
|
|
|
get {
|
|
|
|
|
return true
|
|
|
|
|
}
|
2020-04-27 07:26:04 -07:00
|
|
|
|
}
|
2020-07-11 16:33:29 -07:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func SelectAll() {
|
|
|
|
|
// displayField.currentEditor()?.selectAll(nil)
|
|
|
|
|
displayField.selectText(nil)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func Copy() {
|
|
|
|
|
let pasteBoard = NSPasteboard.general
|
|
|
|
|
pasteBoard.clearContents()
|
|
|
|
|
// TODO: Find a better way to avoid index out of range error when the entire text area is selected
|
|
|
|
|
let string = display.stringValue + " "
|
|
|
|
|
if let selectedRange = displayField.currentEditor()?.selectedRange {
|
|
|
|
|
let startIndex = string.index(string.startIndex, offsetBy: selectedRange.lowerBound)
|
|
|
|
|
let endIndex = string.index(string.startIndex, offsetBy: selectedRange.upperBound)
|
|
|
|
|
let selectedString = string[startIndex..<endIndex]
|
|
|
|
|
pasteBoard.setString(String(selectedString), forType: .string)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func Paste() {
|
|
|
|
|
let pasteBoard = NSPasteboard.general
|
|
|
|
|
if let str = pasteBoard.string( forType: .string ) {
|
|
|
|
|
print("PASTED:", str)
|
|
|
|
|
|
|
|
|
|
DispatchQueue.global(qos: .background).async {
|
|
|
|
|
for char in str.uppercased() {
|
|
|
|
|
if let ascii = char.asciiValue {
|
|
|
|
|
// TODO: Write separate Paste Accelerator
|
|
|
|
|
disk_accelerator_speedup()
|
|
|
|
|
kbdInput(ascii)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-04-27 07:26:04 -07:00
|
|
|
|
|
2020-07-12 21:40:08 -07:00
|
|
|
|
override func mouseMoved(with event: NSEvent) {
|
|
|
|
|
mouseLocation = event.locationInWindow
|
|
|
|
|
|
|
|
|
|
if ( Mouse2Joystick ) {
|
|
|
|
|
pdl_prevarr[0] = pdl_valarr[0]
|
|
|
|
|
pdl_valarr[0] = Double(mouseLocation.x / (displayField.frame.width) )
|
|
|
|
|
pdl_diffarr[0] = pdl_valarr[0] - pdl_prevarr[0]
|
|
|
|
|
|
|
|
|
|
pdl_prevarr[1] = pdl_valarr[1]
|
|
|
|
|
pdl_valarr[1] = 1 - Double(mouseLocation.y / (displayField.frame.height) )
|
|
|
|
|
pdl_diffarr[1] = pdl_valarr[1] - pdl_prevarr[1]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( MouseInterface ) {
|
|
|
|
|
pdl_prevarr[2] = pdl_valarr[2]
|
|
|
|
|
pdl_valarr[2] = Double(mouseLocation.x / (displayField.frame.width) )
|
|
|
|
|
pdl_diffarr[2] = pdl_valarr[2] - pdl_prevarr[2]
|
|
|
|
|
|
|
|
|
|
pdl_prevarr[3] = pdl_valarr[3]
|
|
|
|
|
pdl_valarr[3] = 1 - Double(mouseLocation.y / (displayField.frame.height) )
|
|
|
|
|
pdl_diffarr[3] = pdl_valarr[3] - pdl_prevarr[3]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-09 00:27:31 -07:00
|
|
|
|
override func keyDown(with event: NSEvent) {
|
2020-06-17 09:46:17 -07:00
|
|
|
|
|
|
|
|
|
if ( cpuMode == cpuMode_eco ) {
|
|
|
|
|
cpuState = cpuState_running;
|
2020-06-18 15:14:54 -07:00
|
|
|
|
upd.resume()
|
2020-06-17 09:46:17 -07:00
|
|
|
|
}
|
|
|
|
|
|
2020-06-05 23:16:17 -07:00
|
|
|
|
// print("keyDown")
|
2020-02-22 16:37:54 -08:00
|
|
|
|
|
2020-04-22 19:18:28 -07:00
|
|
|
|
// for i in 0...65536 {
|
|
|
|
|
// ddd = Int(event.keyCode) + i
|
|
|
|
|
// }
|
|
|
|
|
// ddd = ddd * 2
|
|
|
|
|
|
|
|
|
|
|
2019-09-15 04:02:22 -07:00
|
|
|
|
// switch event.modifierFlags.intersection(.deviceIndependentFlagsMask) {
|
|
|
|
|
// case [.command] where event.characters == "l",
|
|
|
|
|
// [.command, .shift] where event.characters == "l":
|
|
|
|
|
// print("command-l or command-shift-l")
|
|
|
|
|
// default:
|
|
|
|
|
// break
|
|
|
|
|
// }
|
|
|
|
|
// print( "key = " + (event.charactersIgnoringModifiers ?? ""))
|
|
|
|
|
// print( "\ncharacter = " + (event.characters ?? ""))
|
2019-09-09 00:27:31 -07:00
|
|
|
|
|
2020-04-22 19:18:28 -07:00
|
|
|
|
|
|
|
|
|
if event.modifierFlags.contains(.command) { // .shift, .option, .control ...
|
|
|
|
|
if let chars = event.charactersIgnoringModifiers {
|
|
|
|
|
switch chars {
|
2020-07-11 16:33:29 -07:00
|
|
|
|
case "a":
|
|
|
|
|
// print("CMD + A")
|
|
|
|
|
SelectAll()
|
|
|
|
|
return // to avoid deselect text
|
2020-04-22 19:18:28 -07:00
|
|
|
|
|
2020-07-11 16:33:29 -07:00
|
|
|
|
case "c":
|
|
|
|
|
// print("CMD + C")
|
|
|
|
|
Copy()
|
|
|
|
|
|
|
|
|
|
case "v":
|
|
|
|
|
// print("CMD + V")
|
|
|
|
|
Paste()
|
2020-07-01 17:47:43 -07:00
|
|
|
|
|
2020-04-22 19:18:28 -07:00
|
|
|
|
default:
|
2020-06-03 10:23:55 -07:00
|
|
|
|
super.keyDown(with: event)
|
2019-09-09 00:27:31 -07:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-04-22 19:18:28 -07:00
|
|
|
|
else {
|
|
|
|
|
#if FUNCTIONTEST
|
|
|
|
|
#else
|
|
|
|
|
let keyCode = Int(event.keyCode)
|
|
|
|
|
switch keyCode {
|
|
|
|
|
case leftArrowKey:
|
2020-06-05 23:16:17 -07:00
|
|
|
|
// print("LEFT", ddd);
|
2020-06-02 10:10:18 -07:00
|
|
|
|
if ( Keyboard2Joystick ) {
|
|
|
|
|
// Keyboard 2 JoyStick (Game Controller / Paddle)
|
|
|
|
|
pdl_valarr[0] = 0
|
|
|
|
|
}
|
|
|
|
|
kbdInput(0x08)
|
2020-05-24 12:14:09 -07:00
|
|
|
|
|
|
|
|
|
|
2020-04-22 19:18:28 -07:00
|
|
|
|
case rightArrowKey:
|
2020-06-05 23:16:17 -07:00
|
|
|
|
// print("RIGHT")
|
2020-05-24 12:14:09 -07:00
|
|
|
|
// Keyboard 2 JoyStick (Game Controller / Paddle)
|
2020-06-02 10:10:18 -07:00
|
|
|
|
if ( Keyboard2Joystick ) {
|
|
|
|
|
pdl_valarr[0] = 1
|
|
|
|
|
}
|
|
|
|
|
kbdInput(0x15)
|
|
|
|
|
|
2020-04-22 19:18:28 -07:00
|
|
|
|
case downArrowKey:
|
2020-06-05 23:16:17 -07:00
|
|
|
|
// print("DOWN")
|
2020-05-24 12:14:09 -07:00
|
|
|
|
// Keyboard 2 JoyStick (Game Controller / Paddle)
|
2020-06-02 10:10:18 -07:00
|
|
|
|
if ( Keyboard2Joystick ) {
|
|
|
|
|
pdl_valarr[1] = 1
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
kbdInput(0x0B)
|
|
|
|
|
}
|
2020-04-22 19:18:28 -07:00
|
|
|
|
case upArrowKey:
|
2020-06-05 23:16:17 -07:00
|
|
|
|
// print("UP")
|
2020-05-24 12:14:09 -07:00
|
|
|
|
// Keyboard 2 JoyStick (Game Controller / Paddle)
|
2020-06-02 10:10:18 -07:00
|
|
|
|
if ( Keyboard2Joystick ) {
|
|
|
|
|
pdl_valarr[1] = 0
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
kbdInput(0x0A)
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-22 19:18:28 -07:00
|
|
|
|
default:
|
|
|
|
|
// print("keycode: %d", keyCode)
|
|
|
|
|
if let chars = event.characters {
|
|
|
|
|
let char = chars.uppercased()[chars.startIndex]
|
|
|
|
|
if let ascii = char.asciiValue {
|
|
|
|
|
kbdInput(ascii)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
2020-04-27 07:26:04 -07:00
|
|
|
|
|
2020-07-01 17:47:43 -07:00
|
|
|
|
displayField.currentEditor()?.selectedRange = NSMakeRange(0, 0)
|
2019-09-09 00:27:31 -07:00
|
|
|
|
}
|
|
|
|
|
|
2020-05-05 23:03:36 -07:00
|
|
|
|
|
|
|
|
|
var savedVideoMode = videoMode_t.init()
|
|
|
|
|
|
|
|
|
|
|
2020-02-22 16:37:54 -08:00
|
|
|
|
override func keyUp(with event: NSEvent) {
|
2020-06-05 23:16:17 -07:00
|
|
|
|
// print("keyUp")
|
2020-02-22 16:37:54 -08:00
|
|
|
|
// switch event.modifierFlags.intersection(.deviceIndependentFlagsMask) {
|
|
|
|
|
// case [.command] where event.characters == "l",
|
|
|
|
|
// [.command, .shift] where event.characters == "l":
|
|
|
|
|
// print("command-l or command-shift-l")
|
|
|
|
|
// default:
|
|
|
|
|
// break
|
|
|
|
|
// }
|
|
|
|
|
// print( "key = " + (event.charactersIgnoringModifiers ?? ""))
|
|
|
|
|
// print( "\ncharacter = " + (event.characters ?? ""))
|
|
|
|
|
|
|
|
|
|
#if FUNCTIONTEST
|
|
|
|
|
#else
|
|
|
|
|
let keyCode = Int(event.keyCode)
|
|
|
|
|
switch keyCode {
|
|
|
|
|
case leftArrowKey:
|
|
|
|
|
// kbdInput(0x08)
|
2020-05-24 12:14:09 -07:00
|
|
|
|
// setIO(0xC064, 127);
|
2020-06-05 23:16:17 -07:00
|
|
|
|
// print("left")
|
2020-05-24 12:14:09 -07:00
|
|
|
|
// Keyboard 2 JoyStick (Game Controller / Paddle)
|
|
|
|
|
pdl_valarr[0] = 0.5
|
|
|
|
|
|
2020-02-22 16:37:54 -08:00
|
|
|
|
case rightArrowKey:
|
|
|
|
|
// kbdInput(0x15)
|
2020-05-24 12:14:09 -07:00
|
|
|
|
// setIO(0xC064, 128);
|
2020-06-05 23:16:17 -07:00
|
|
|
|
// print("right")
|
2020-05-24 12:14:09 -07:00
|
|
|
|
// Keyboard 2 JoyStick (Game Controller / Paddle)
|
|
|
|
|
pdl_valarr[0] = 0.5
|
|
|
|
|
|
2020-02-22 16:37:54 -08:00
|
|
|
|
case downArrowKey:
|
|
|
|
|
// kbdInput(0x0B)
|
2020-05-24 12:14:09 -07:00
|
|
|
|
// setIO(0xC065, 127);
|
2020-06-05 23:16:17 -07:00
|
|
|
|
// print("down")
|
2020-05-24 12:14:09 -07:00
|
|
|
|
// Keyboard 2 JoyStick (Game Controller / Paddle)
|
|
|
|
|
pdl_valarr[1] = 0.5
|
|
|
|
|
|
2020-02-22 16:37:54 -08:00
|
|
|
|
case upArrowKey:
|
|
|
|
|
// kbdInput(0x0A)
|
2020-05-24 12:14:09 -07:00
|
|
|
|
// setIO(0xC065, 128);
|
2020-06-05 23:16:17 -07:00
|
|
|
|
// print("up")
|
2020-05-24 12:14:09 -07:00
|
|
|
|
// Keyboard 2 JoyStick (Game Controller / Paddle)
|
|
|
|
|
pdl_valarr[1] = 0.5
|
|
|
|
|
|
2020-02-22 16:37:54 -08:00
|
|
|
|
default:
|
|
|
|
|
// print("keycode: %d", keyCode)
|
|
|
|
|
// if let chars = event.characters {
|
|
|
|
|
// let char = chars.uppercased()[chars.startIndex]
|
|
|
|
|
// if let ascii = char.asciiValue {
|
|
|
|
|
// kbdInput(ascii)
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2020-05-05 08:35:57 -07:00
|
|
|
|
kbdUp()
|
|
|
|
|
|
2020-02-22 16:37:54 -08:00
|
|
|
|
}
|
2020-05-20 22:22:44 -07:00
|
|
|
|
|
|
|
|
|
override func flagsChanged(with event: NSEvent) {
|
|
|
|
|
switch event.modifierFlags.intersection(.deviceIndependentFlagsMask) {
|
|
|
|
|
case [.shift]:
|
2020-06-24 21:05:55 -07:00
|
|
|
|
setIO(0xC061, 0)
|
|
|
|
|
setIO(0xC062, 0)
|
|
|
|
|
setIO(0xC063, 0) // inverted (bit 7: not pressed)
|
2020-06-05 23:16:17 -07:00
|
|
|
|
// print("shift key is pressed")
|
|
|
|
|
// case [.control]:
|
|
|
|
|
// print("control key is pressed")
|
2020-05-20 22:22:44 -07:00
|
|
|
|
case [.option] :
|
2020-06-28 21:00:25 -07:00
|
|
|
|
setIO(0xC061, 0)
|
|
|
|
|
setIO(0xC062, 1 << 7)
|
2020-06-24 21:05:55 -07:00
|
|
|
|
setIO(0xC063, 1 << 7) // inverted (bit 7: not pressed)
|
2020-06-05 23:16:17 -07:00
|
|
|
|
// print("option key is pressed")
|
2020-05-20 22:22:44 -07:00
|
|
|
|
case [.command]:
|
2020-06-05 23:16:17 -07:00
|
|
|
|
// print("Command key is pressed")
|
2020-06-28 21:00:25 -07:00
|
|
|
|
setIO(0xC061, 1 << 7)
|
|
|
|
|
setIO(0xC062, 0)
|
2020-06-24 21:05:55 -07:00
|
|
|
|
setIO(0xC063, 1 << 7) // inverted (bit 7: not pressed)
|
2020-06-05 23:16:17 -07:00
|
|
|
|
// case [.control, .shift]:
|
|
|
|
|
// print("control-shift keys are pressed")
|
2020-05-20 22:22:44 -07:00
|
|
|
|
case [.option, .shift]:
|
2020-06-24 21:05:55 -07:00
|
|
|
|
setIO(0xC061, 1 << 7)
|
|
|
|
|
setIO(0xC062, 0)
|
|
|
|
|
setIO(0xC063, 0) // inverted (bit 7: not pressed)
|
2020-06-05 23:16:17 -07:00
|
|
|
|
// print("option-shift keys are pressed")
|
2020-05-20 22:22:44 -07:00
|
|
|
|
case [.command, .shift]:
|
2020-06-28 21:00:25 -07:00
|
|
|
|
setIO(0xC061, 1 << 7)
|
|
|
|
|
setIO(0xC062, 0)
|
2020-06-24 21:05:55 -07:00
|
|
|
|
setIO(0xC063, 0) // inverted (bit 7: not pressed)
|
2020-06-05 23:16:17 -07:00
|
|
|
|
// print("command-shift keys are pressed")
|
|
|
|
|
// case [.control, .option]:
|
|
|
|
|
// print("control-option keys are pressed")
|
|
|
|
|
// case [.control, .command]:
|
|
|
|
|
// print("control-command keys are pressed")
|
2020-05-20 22:22:44 -07:00
|
|
|
|