it runs Integer BASIC! (but can't load cassettes so it's just hardcoded to load it at $E000)

This commit is contained in:
Luigi Thirty 2017-07-29 22:48:37 -04:00
parent 76e8801611
commit 447b39a2d0
8 changed files with 54 additions and 25 deletions

View File

@ -23,7 +23,7 @@ class AppleI: NSObject {
] ]
let emulatorViewDelegate = AppleScreenViewDelegate() let emulatorViewDelegate = AppleScreenViewDelegate()
let emulatorView = AppleScreenView(frame: NSMakeRect(0, 0, 400, 384)) let emulatorView = AppleScreenView(frame: NSMakeRect(0, 0, 640, 384))
let emuScreenLayer = CALayer() let emuScreenLayer = CALayer()
static let CPU_FREQUENCY = 1000000 static let CPU_FREQUENCY = 1000000
@ -49,7 +49,8 @@ class AppleI: NSObject {
emulatorViewDelegate.putCharacterPixels(charPixels: cg.getCharacterPixels(charIndex: character), pixelPosition: emulatorViewDelegate.getPixelOffset(charCellIndex: cellNum)) 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() CPU.sharedInstance.performReset()
} }

View File

@ -9,8 +9,8 @@
import Cocoa import Cocoa
class AppleScreenViewDelegate: NSObject, CALayerDelegate { class AppleScreenViewDelegate: NSObject, CALayerDelegate {
let PIXEL_WIDTH = 200 static let PIXEL_WIDTH = 320
let PIXEL_HEIGHT = 192 static let PIXEL_HEIGHT = 192
/* Pixel data stuff. */ /* Pixel data stuff. */
struct PixelData { struct PixelData {
@ -19,6 +19,7 @@ class AppleScreenViewDelegate: NSObject, CALayerDelegate {
var g: UInt8 var g: UInt8
var b: UInt8 var b: UInt8
} }
let bitsPerComponent: UInt = 8 let bitsPerComponent: UInt = 8
let bitsPerPixel: UInt = 32 let bitsPerPixel: UInt = 32
let colorSpace = CGColorSpaceCreateDeviceRGB() let colorSpace = CGColorSpaceCreateDeviceRGB()
@ -28,17 +29,17 @@ class AppleScreenViewDelegate: NSObject, CALayerDelegate {
var indexedPixels: [UInt8] var indexedPixels: [UInt8]
var colorValues: [PixelData] 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() 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 = [PixelData](repeating: PixelData(a: 255, r: 0, g: 0, b: 0), count: 256)
colorValues[1] = PixelData(a: 0, r: 200, g: 200, b: 200 colorValues[1] = PixelData(a: 0, r: 200, g: 200, b: 200
) )
} }
func convertIndexedPixelsToRGB(pixels: [UInt8]) -> [PixelData] { 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() { for (num, colorIndex) in pixels.enumerated() {
rgbPixels[num] = colorValues[Int(colorIndex)] rgbPixels[num] = colorValues[Int(colorIndex)]
} }
@ -48,17 +49,18 @@ class AppleScreenViewDelegate: NSObject, CALayerDelegate {
func putCharacterPixels(charPixels: [UInt8], pixelPosition: CGPoint) { func putCharacterPixels(charPixels: [UInt8], pixelPosition: CGPoint) {
//Calculate the offset to reach the desired position. //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 charY in 0..<CharacterGenerator.CHAR_HEIGHT {
for charX in 0..<CharacterGenerator.CHAR_WIDTH { //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..<8 {
indexedPixels[baseOffset + (AppleScreenViewDelegate.PIXEL_WIDTH * charY) + 7 - charX] = (charPixels[charY] & UInt8(1 << charX)) > 0 ? 1 : 0
} }
} }
} }
func getPixelOffset(charCellX: Int, charCellY: Int) -> CGPoint { 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 { func getPixelOffset(charCellIndex: Int) -> CGPoint {
@ -68,12 +70,21 @@ class AppleScreenViewDelegate: NSObject, CALayerDelegate {
/* Draw the screen. */ /* Draw the screen. */
func draw(_ layer: CALayer, in ctx: CGContext) { func draw(_ layer: CALayer, in ctx: CGContext) {
let bounds = layer.bounds let bounds = layer.bounds
ctx.interpolationQuality = CGInterpolationQuality.none
var pixels = convertIndexedPixelsToRGB(pixels: indexedPixels) var pixels = convertIndexedPixelsToRGB(pixels: indexedPixels)
let pixelProvider = CGDataProvider(data: NSData(bytes: &pixels, length: pixels.count * MemoryLayout<PixelData>.size)) 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) ctx.draw(renderedImage!, in: bounds)
} }

View File

@ -16,6 +16,7 @@ struct Cell {
class Terminal: NSObject { class Terminal: NSObject {
static let CELLS_WIDTH = 40 static let CELLS_WIDTH = 40
static let CELLS_HEIGHT = 24 static let CELLS_HEIGHT = 24
static let CELLS_COUNT = CELLS_WIDTH * CELLS_HEIGHT
var cursorPosition: Cell var cursorPosition: Cell
var characters: [UInt8] var characters: [UInt8]
@ -45,8 +46,9 @@ class Terminal: NSObject {
if(cursorPosition.x == Terminal.CELLS_WIDTH) { if(cursorPosition.x == Terminal.CELLS_WIDTH) {
cursorPosition.x = 0 cursorPosition.x = 0
cursorPosition.y += 1 cursorPosition.y += 1
if(cursorPosition.y == Terminal.CELLS_HEIGHT) { if(cursorPosition.y >= Terminal.CELLS_HEIGHT) {
cursorPosition.y = 0 //TODO: scrolling cursorPosition.y = Terminal.CELLS_HEIGHT - 1
scrollUp(lines: 1)
} }
} }
} }
@ -54,8 +56,15 @@ class Terminal: NSObject {
func carriageReturn() { func carriageReturn() {
cursorPosition.x = 0 cursorPosition.x = 0
cursorPosition.y += 1 cursorPosition.y += 1
if(cursorPosition.y == Terminal.CELLS_HEIGHT) { if(cursorPosition.y >= Terminal.CELLS_HEIGHT) {
cursorPosition.y = 0 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))
}
} }

View File

@ -698,7 +698,7 @@
<windowController id="0Wh-dg-gsU" sceneMemberID="viewController"> <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"> <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"/> <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"/> <rect key="screenRect" x="0.0" y="0.0" width="1916" height="936"/>
<connections> <connections>
<outlet property="delegate" destination="0Wh-dg-gsU" id="tmJ-Ae-YJP"/> <outlet property="delegate" destination="0Wh-dg-gsU" id="tmJ-Ae-YJP"/>
@ -717,7 +717,7 @@
<objects> <objects>
<viewController id="gw1-M7-9Je" customClass="MainViewController" customModule="FruitMachine" customModuleProvider="target" sceneMemberID="viewController"> <viewController id="gw1-M7-9Je" customClass="MainViewController" customModule="FruitMachine" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" id="DiY-xb-Usb"> <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"/> <autoresizingMask key="autoresizingMask"/>
</view> </view>
</viewController> </viewController>

View File

@ -47,6 +47,7 @@ class DebuggerViewController: NSViewController {
text_CPU_Flags.stringValue = String(cpuInstance.status_register.asString()) text_CPU_Flags.stringValue = String(cpuInstance.status_register.asString())
disassembly = cpuInstance.disassemble(fromAddress: CPU.sharedInstance.program_counter, length: 256) disassembly = cpuInstance.disassemble(fromAddress: CPU.sharedInstance.program_counter, length: 256)
debuggerTableView.reloadData()
highlightCurrentInstruction() highlightCurrentInstruction()
} }

View File

@ -60,10 +60,10 @@ class MemoryInterface: NSObject {
return (UInt16(high) << 8) | UInt16(low) return (UInt16(high) << 8) | UInt16(low)
} }
func loadBinary(path: String, offset: UInt16) { func loadBinary(path: String, offset: UInt16, length: Int) {
do { do {
let fileContent: NSData = try NSData(contentsOfFile: path) 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 { } catch {
print(error) print(error)
} }

View File

@ -173,7 +173,7 @@ class Opcodes: NSObject {
static func SBC(state: CPU, addressingMode: AddressingMode) -> Void { static func SBC(state: CPU, addressingMode: AddressingMode) -> Void {
let operand = UInt8(getOperandByteForAddressingMode(state: state, mode: addressingMode)) 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) let t8: UInt8 = UInt8(t16 & 0xFF)
state.cyclesInBatch = 0 state.cyclesInBatch = 0
@ -182,7 +182,7 @@ class Opcodes: NSObject {
if(state.status_register.decimal == true) { if(state.status_register.decimal == true) {
t16 = UInt16(hex2bcd(hex: state.accumulator) + hex2bcd(hex: operand) + (state.status_register.carry ? UInt8(1) : UInt8(0))) t16 = UInt16(hex2bcd(hex: state.accumulator) + hex2bcd(hex: operand) + (state.status_register.carry ? UInt8(1) : UInt8(0)))
} else { } else {
state.status_register.carry = (t16 >> 8) == 0 ? false : true state.status_register.carry = t8 <= 127 ? true : false
} }
state.accumulator = t8 state.accumulator = t8

View File

@ -28,18 +28,25 @@ class MainViewController: NSViewController {
self.view.addSubview(computer.emulatorView) self.view.addSubview(computer.emulatorView)
self.frameTimer = Timer.scheduledTimer(timeInterval: 1/60, target: self, selector: #selector(runEmulation), userInfo: nil, repeats: true) self.frameTimer = Timer.scheduledTimer(timeInterval: 1/60, target: self, selector: #selector(runEmulation), userInfo: nil, repeats: true)
//runEmulation()
} }
@objc func runEmulation() { @objc func runEmulation() {
computer.runFrame() computer.runFrame()
if(!CPU.sharedInstance.isRunning) {
self.frameTimer?.invalidate()
}
} }
override func keyDown(with event: NSEvent) { override func keyDown(with event: NSEvent) {
let c = returnChar(theEvent: event) 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 computer.pia["keyboard"]?.control |= 0x80
} }
private func returnChar(theEvent: NSEvent) -> Character?{ private func returnChar(theEvent: NSEvent) -> Character?{