mirror of
https://github.com/Luigi30/FruitMachine-Swift.git
synced 2024-11-23 02:33:00 +00:00
it runs Integer BASIC! (but can't load cassettes so it's just hardcoded to load it at $E000)
This commit is contained in:
parent
76e8801611
commit
447b39a2d0
@ -23,7 +23,7 @@ class AppleI: NSObject {
|
||||
]
|
||||
|
||||
let emulatorViewDelegate = AppleScreenViewDelegate()
|
||||
let emulatorView = AppleScreenView(frame: NSMakeRect(0, 0, 400, 384))
|
||||
let emulatorView = AppleScreenView(frame: NSMakeRect(0, 0, 640, 384))
|
||||
let emuScreenLayer = CALayer()
|
||||
|
||||
static let CPU_FREQUENCY = 1000000
|
||||
@ -49,7 +49,8 @@ class AppleI: NSObject {
|
||||
emulatorViewDelegate.putCharacterPixels(charPixels: cg.getCharacterPixels(charIndex: character), pixelPosition: emulatorViewDelegate.getPixelOffset(charCellIndex: cellNum))
|
||||
}
|
||||
|
||||
CPU.sharedInstance.memoryInterface.loadBinary(path: "/Users/luigi/apple1/apple1.rom", offset: 0xFF00)
|
||||
CPU.sharedInstance.memoryInterface.loadBinary(path: "/Users/luigi/apple1/apple1.rom", offset: 0xFF00, length: 0x100)
|
||||
CPU.sharedInstance.memoryInterface.loadBinary(path: "/Users/luigi/apple1/basic.bin", offset: 0xE000, length: 0x1000)
|
||||
CPU.sharedInstance.performReset()
|
||||
|
||||
}
|
||||
|
@ -9,8 +9,8 @@
|
||||
import Cocoa
|
||||
|
||||
class AppleScreenViewDelegate: NSObject, CALayerDelegate {
|
||||
let PIXEL_WIDTH = 200
|
||||
let PIXEL_HEIGHT = 192
|
||||
static let PIXEL_WIDTH = 320
|
||||
static let PIXEL_HEIGHT = 192
|
||||
|
||||
/* Pixel data stuff. */
|
||||
struct PixelData {
|
||||
@ -19,6 +19,7 @@ class AppleScreenViewDelegate: NSObject, CALayerDelegate {
|
||||
var g: UInt8
|
||||
var b: UInt8
|
||||
}
|
||||
|
||||
let bitsPerComponent: UInt = 8
|
||||
let bitsPerPixel: UInt = 32
|
||||
let colorSpace = CGColorSpaceCreateDeviceRGB()
|
||||
@ -28,17 +29,17 @@ class AppleScreenViewDelegate: NSObject, CALayerDelegate {
|
||||
var indexedPixels: [UInt8]
|
||||
var colorValues: [PixelData]
|
||||
|
||||
var rgbPixels = [PixelData](repeating: PixelData(a: 255, r: 0, g: 0, b: 0), count: AppleScreenViewDelegate.PIXEL_WIDTH*AppleScreenViewDelegate.PIXEL_HEIGHT)
|
||||
|
||||
override init()
|
||||
{
|
||||
indexedPixels = [UInt8](repeating: 0x00, count: 200*192)
|
||||
indexedPixels = [UInt8](repeating: 0x00, count: AppleScreenViewDelegate.PIXEL_WIDTH*AppleScreenViewDelegate.PIXEL_HEIGHT)
|
||||
colorValues = [PixelData](repeating: PixelData(a: 255, r: 0, g: 0, b: 0), count: 256)
|
||||
colorValues[1] = PixelData(a: 0, r: 200, g: 200, b: 200
|
||||
)
|
||||
}
|
||||
|
||||
func convertIndexedPixelsToRGB(pixels: [UInt8]) -> [PixelData] {
|
||||
var rgbPixels = [PixelData](repeating: PixelData(a: 255, r: 0, g: 0, b: 0), count: 200*192)
|
||||
|
||||
for (num, colorIndex) in pixels.enumerated() {
|
||||
rgbPixels[num] = colorValues[Int(colorIndex)]
|
||||
}
|
||||
@ -48,17 +49,18 @@ class AppleScreenViewDelegate: NSObject, CALayerDelegate {
|
||||
|
||||
func putCharacterPixels(charPixels: [UInt8], pixelPosition: CGPoint) {
|
||||
//Calculate the offset to reach the desired position.
|
||||
let baseOffset = (Int(pixelPosition.y) * PIXEL_WIDTH) + Int(pixelPosition.x)
|
||||
let baseOffset = (Int(pixelPosition.y) * AppleScreenViewDelegate.PIXEL_WIDTH) + Int(pixelPosition.x)
|
||||
|
||||
for charY in 0..<CharacterGenerator.CHAR_HEIGHT {
|
||||
for charX in 0..<CharacterGenerator.CHAR_WIDTH {
|
||||
indexedPixels[baseOffset + (PIXEL_WIDTH * charY) + CharacterGenerator.CHAR_WIDTH - charX - 1] = (charPixels[charY] & UInt8(1 << charX)) > 0 ? 1 : 0
|
||||
//for charX in 0..<CharacterGenerator.CHAR_WIDTH {
|
||||
for charX in 0..<8 {
|
||||
indexedPixels[baseOffset + (AppleScreenViewDelegate.PIXEL_WIDTH * charY) + 7 - charX] = (charPixels[charY] & UInt8(1 << charX)) > 0 ? 1 : 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getPixelOffset(charCellX: Int, charCellY: Int) -> CGPoint {
|
||||
return CGPoint(x: charCellX * 5, y: charCellY * 8)
|
||||
return CGPoint(x: charCellX * 8, y: charCellY * 8)
|
||||
}
|
||||
|
||||
func getPixelOffset(charCellIndex: Int) -> CGPoint {
|
||||
@ -68,12 +70,21 @@ class AppleScreenViewDelegate: NSObject, CALayerDelegate {
|
||||
/* Draw the screen. */
|
||||
func draw(_ layer: CALayer, in ctx: CGContext) {
|
||||
let bounds = layer.bounds
|
||||
ctx.interpolationQuality = CGInterpolationQuality.none
|
||||
|
||||
var pixels = convertIndexedPixelsToRGB(pixels: indexedPixels)
|
||||
let pixelProvider = CGDataProvider(data: NSData(bytes: &pixels, length: pixels.count * MemoryLayout<PixelData>.size))
|
||||
|
||||
let renderedImage = CGImage(width: PIXEL_WIDTH, height: PIXEL_HEIGHT, bitsPerComponent: Int(bitsPerComponent), bitsPerPixel: Int(bitsPerPixel), bytesPerRow: PIXEL_WIDTH * Int(MemoryLayout<PixelData>.size), space: colorSpace, bitmapInfo: bitmapInfo, provider: pixelProvider!, decode: nil, shouldInterpolate: true, intent: CGColorRenderingIntent.defaultIntent)
|
||||
let renderedImage = CGImage(width: AppleScreenViewDelegate.PIXEL_WIDTH,
|
||||
height: AppleScreenViewDelegate.PIXEL_HEIGHT,
|
||||
bitsPerComponent: Int(bitsPerComponent),
|
||||
bitsPerPixel: Int(bitsPerPixel),
|
||||
bytesPerRow: AppleScreenViewDelegate.PIXEL_WIDTH * Int(MemoryLayout<PixelData>.size),
|
||||
space: colorSpace,
|
||||
bitmapInfo: bitmapInfo,
|
||||
provider: pixelProvider!,
|
||||
decode: nil,
|
||||
shouldInterpolate: false,
|
||||
intent: CGColorRenderingIntent.defaultIntent)
|
||||
|
||||
ctx.draw(renderedImage!, in: bounds)
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ struct Cell {
|
||||
class Terminal: NSObject {
|
||||
static let CELLS_WIDTH = 40
|
||||
static let CELLS_HEIGHT = 24
|
||||
static let CELLS_COUNT = CELLS_WIDTH * CELLS_HEIGHT
|
||||
|
||||
var cursorPosition: Cell
|
||||
var characters: [UInt8]
|
||||
@ -45,8 +46,9 @@ class Terminal: NSObject {
|
||||
if(cursorPosition.x == Terminal.CELLS_WIDTH) {
|
||||
cursorPosition.x = 0
|
||||
cursorPosition.y += 1
|
||||
if(cursorPosition.y == Terminal.CELLS_HEIGHT) {
|
||||
cursorPosition.y = 0 //TODO: scrolling
|
||||
if(cursorPosition.y >= Terminal.CELLS_HEIGHT) {
|
||||
cursorPosition.y = Terminal.CELLS_HEIGHT - 1
|
||||
scrollUp(lines: 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -54,8 +56,15 @@ class Terminal: NSObject {
|
||||
func carriageReturn() {
|
||||
cursorPosition.x = 0
|
||||
cursorPosition.y += 1
|
||||
if(cursorPosition.y == Terminal.CELLS_HEIGHT) {
|
||||
cursorPosition.y = 0
|
||||
if(cursorPosition.y >= Terminal.CELLS_HEIGHT) {
|
||||
cursorPosition.y = Terminal.CELLS_HEIGHT - 1
|
||||
scrollUp(lines: 1)
|
||||
}
|
||||
}
|
||||
|
||||
func scrollUp(lines: Int) {
|
||||
let scrolled = characters[Terminal.CELLS_WIDTH ..< Terminal.CELLS_COUNT]
|
||||
characters = [UInt8](scrolled)
|
||||
characters.append(contentsOf: [UInt8](repeating: 0x00, count: Terminal.CELLS_WIDTH))
|
||||
}
|
||||
}
|
||||
|
@ -698,7 +698,7 @@
|
||||
<windowController id="0Wh-dg-gsU" sceneMemberID="viewController">
|
||||
<window key="window" title="Fruit Machine" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" showsToolbarButton="NO" frameAutosaveName="" animationBehavior="default" id="O0r-h6-7La">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
|
||||
<rect key="contentRect" x="293" y="264" width="480" height="360"/>
|
||||
<rect key="contentRect" x="293" y="264" width="640" height="360"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="1916" height="936"/>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="0Wh-dg-gsU" id="tmJ-Ae-YJP"/>
|
||||
@ -717,7 +717,7 @@
|
||||
<objects>
|
||||
<viewController id="gw1-M7-9Je" customClass="MainViewController" customModule="FruitMachine" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" id="DiY-xb-Usb">
|
||||
<rect key="frame" x="0.0" y="0.0" width="400" height="384"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="640" height="384"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</view>
|
||||
</viewController>
|
||||
|
@ -47,6 +47,7 @@ class DebuggerViewController: NSViewController {
|
||||
text_CPU_Flags.stringValue = String(cpuInstance.status_register.asString())
|
||||
|
||||
disassembly = cpuInstance.disassemble(fromAddress: CPU.sharedInstance.program_counter, length: 256)
|
||||
debuggerTableView.reloadData()
|
||||
highlightCurrentInstruction()
|
||||
}
|
||||
|
||||
|
@ -60,10 +60,10 @@ class MemoryInterface: NSObject {
|
||||
return (UInt16(high) << 8) | UInt16(low)
|
||||
}
|
||||
|
||||
func loadBinary(path: String, offset: UInt16) {
|
||||
func loadBinary(path: String, offset: UInt16, length: Int) {
|
||||
do {
|
||||
let fileContent: NSData = try NSData(contentsOfFile: path)
|
||||
fileContent.getBytes(&memory[Int(offset)], range: NSRange(location: 0, length: 256))
|
||||
fileContent.getBytes(&memory[Int(offset)], range: NSRange(location: 0, length: length))
|
||||
} catch {
|
||||
print(error)
|
||||
}
|
||||
|
@ -173,7 +173,7 @@ class Opcodes: NSObject {
|
||||
|
||||
static func SBC(state: CPU, addressingMode: 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)))
|
||||
var t16: UInt16 = UInt16(state.accumulator &- operand) &- UInt16((state.status_register.carry ? UInt8(0) : UInt8(1)))
|
||||
let t8: UInt8 = UInt8(t16 & 0xFF)
|
||||
|
||||
state.cyclesInBatch = 0
|
||||
@ -182,7 +182,7 @@ class Opcodes: NSObject {
|
||||
if(state.status_register.decimal == true) {
|
||||
t16 = UInt16(hex2bcd(hex: state.accumulator) + hex2bcd(hex: operand) + (state.status_register.carry ? UInt8(1) : UInt8(0)))
|
||||
} else {
|
||||
state.status_register.carry = (t16 >> 8) == 0 ? false : true
|
||||
state.status_register.carry = t8 <= 127 ? true : false
|
||||
}
|
||||
|
||||
state.accumulator = t8
|
||||
|
@ -28,18 +28,25 @@ class MainViewController: NSViewController {
|
||||
self.view.addSubview(computer.emulatorView)
|
||||
|
||||
self.frameTimer = Timer.scheduledTimer(timeInterval: 1/60, target: self, selector: #selector(runEmulation), userInfo: nil, repeats: true)
|
||||
//runEmulation()
|
||||
}
|
||||
|
||||
@objc func runEmulation() {
|
||||
computer.runFrame()
|
||||
if(!CPU.sharedInstance.isRunning) {
|
||||
self.frameTimer?.invalidate()
|
||||
}
|
||||
}
|
||||
|
||||
override func keyDown(with event: NSEvent) {
|
||||
let c = returnChar(theEvent: event)
|
||||
|
||||
computer.pia["keyboard"]?.data = UInt8((c?.asciiValue)! & 0x000000FF)
|
||||
guard let ascii32 = c?.asciiValue else {
|
||||
return
|
||||
}
|
||||
|
||||
computer.pia["keyboard"]?.data = UInt8(ascii32 & 0x000000FF)
|
||||
computer.pia["keyboard"]?.control |= 0x80
|
||||
|
||||
}
|
||||
|
||||
private func returnChar(theEvent: NSEvent) -> Character?{
|
||||
|
Loading…
Reference in New Issue
Block a user