mirror of
https://github.com/TomHarte/CLK.git
synced 2025-02-09 02:31:22 +00:00
Added enough infrastructure to be able to react to the two CP/M calls this cares about.
This commit is contained in:
parent
62b432c046
commit
d910405648
@ -11,17 +11,23 @@
|
|||||||
typedef NS_ENUM(NSInteger, CSTestMachineZ80Register) {
|
typedef NS_ENUM(NSInteger, CSTestMachineZ80Register) {
|
||||||
CSTestMachineZ80RegisterProgramCounter,
|
CSTestMachineZ80RegisterProgramCounter,
|
||||||
CSTestMachineZ80RegisterStackPointer,
|
CSTestMachineZ80RegisterStackPointer,
|
||||||
|
|
||||||
|
CSTestMachineZ80RegisterC,
|
||||||
|
CSTestMachineZ80RegisterE,
|
||||||
|
CSTestMachineZ80RegisterDE,
|
||||||
};
|
};
|
||||||
|
|
||||||
@class CSTestMachineZ80;
|
@class CSTestMachineZ80;
|
||||||
|
|
||||||
@interface CSTestMachineTrapHandler
|
@protocol CSTestMachineTrapHandler
|
||||||
- (void)testMachine:(CSTestMachineZ80 *)testMachine didTrapAtAddress:(uint16_t)address;
|
- (void)testMachine:(CSTestMachineZ80 *)testMachine didTrapAtAddress:(uint16_t)address;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@interface CSTestMachineZ80 : NSObject
|
@interface CSTestMachineZ80 : NSObject
|
||||||
|
|
||||||
- (void)setData:(NSData *)data atAddress:(uint16_t)startAddress;
|
- (void)setData:(NSData *)data atAddress:(uint16_t)startAddress;
|
||||||
|
- (void)setValue:(uint8_t)value atAddress:(uint16_t)address;
|
||||||
|
- (uint8_t)valueAtAddress:(uint16_t)address;
|
||||||
- (void)runForNumberOfCycles:(int)cycles;
|
- (void)runForNumberOfCycles:(int)cycles;
|
||||||
|
|
||||||
- (void)setValue:(uint16_t)value forRegister:(CSTestMachineZ80Register)reg;
|
- (void)setValue:(uint16_t)value forRegister:(CSTestMachineZ80Register)reg;
|
||||||
|
@ -33,6 +33,9 @@ static CPU::Z80::Register registerForRegister(CSTestMachineZ80Register reg) {
|
|||||||
switch (reg) {
|
switch (reg) {
|
||||||
case CSTestMachineZ80RegisterProgramCounter: return CPU::Z80::Register::ProgramCounter;
|
case CSTestMachineZ80RegisterProgramCounter: return CPU::Z80::Register::ProgramCounter;
|
||||||
case CSTestMachineZ80RegisterStackPointer: return CPU::Z80::Register::StackPointer;
|
case CSTestMachineZ80RegisterStackPointer: return CPU::Z80::Register::StackPointer;
|
||||||
|
case CSTestMachineZ80RegisterC: return CPU::Z80::Register::C;
|
||||||
|
case CSTestMachineZ80RegisterE: return CPU::Z80::Register::E;
|
||||||
|
case CSTestMachineZ80RegisterDE: return CPU::Z80::Register::DE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,6 +74,16 @@ static CPU::Z80::Register registerForRegister(CSTestMachineZ80Register reg) {
|
|||||||
_processor.set_value_of_register(registerForRegister(reg), value);
|
_processor.set_value_of_register(registerForRegister(reg), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setValue:(uint8_t)value atAddress:(uint16_t)address {
|
||||||
|
_processor.set_data_at_address(address, 1, &value);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (uint8_t)valueAtAddress:(uint16_t)address {
|
||||||
|
uint8_t value;
|
||||||
|
_processor.get_data_at_address(address, 1, &value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
- (uint16_t)valueForRegister:(CSTestMachineZ80Register)reg {
|
- (uint16_t)valueForRegister:(CSTestMachineZ80Register)reg {
|
||||||
return _processor.get_value_of_register(registerForRegister(reg));
|
return _processor.get_value_of_register(registerForRegister(reg));
|
||||||
}
|
}
|
||||||
|
@ -9,21 +9,49 @@
|
|||||||
import XCTest
|
import XCTest
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
class ZexallTests: XCTestCase {
|
class ZexallTests: XCTestCase, CSTestMachineTrapHandler {
|
||||||
|
|
||||||
func testZexall() {
|
func testZexall() {
|
||||||
if let filename = Bundle(for: type(of: self)).path(forResource: "zexall", ofType: "com") {
|
if let filename = Bundle(for: type(of: self)).path(forResource: "zexall", ofType: "com") {
|
||||||
if let testData = try? Data(contentsOf: URL(fileURLWithPath: filename)) {
|
if let testData = try? Data(contentsOf: URL(fileURLWithPath: filename)) {
|
||||||
|
|
||||||
|
// install test program, at the usual CP/M place
|
||||||
let machine = CSTestMachineZ80()
|
let machine = CSTestMachineZ80()
|
||||||
machine.setData(testData, atAddress: 0x0100)
|
machine.setData(testData, atAddress: 0x0100)
|
||||||
|
|
||||||
machine.setValue(0x0100, for: .programCounter)
|
// add a RET at the CP/M entry location, and establish it as a trap location
|
||||||
machine.setValue(0xffff, for: .stackPointer)
|
machine.setValue(0xc9, atAddress: 0x0005)
|
||||||
|
machine.addTrapAddress(0x0005);
|
||||||
|
machine.trapHandler = self
|
||||||
|
|
||||||
|
// seed execution at 0x0100
|
||||||
|
machine.setValue(0x0100, for: .programCounter)
|
||||||
|
|
||||||
|
// run!
|
||||||
machine.runForNumber(ofCycles: 20)
|
machine.runForNumber(ofCycles: 20)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testMachine(_ testMachine: CSTestMachineZ80!, didTrapAtAddress address: UInt16) {
|
||||||
|
// only 0x0005 was registered as a trap address, so no need further to inspect
|
||||||
|
let cRegister = testMachine.value(for: .C)
|
||||||
|
if cRegister == 9 {
|
||||||
|
var address = testMachine.value(for: .DE)
|
||||||
|
var character: Character = " "
|
||||||
|
var output = ""
|
||||||
|
while true {
|
||||||
|
character = Character(UnicodeScalar(testMachine.value(atAddress: address)))
|
||||||
|
if character == "$" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
output = output + String(character)
|
||||||
|
address = address + 1
|
||||||
|
}
|
||||||
|
print(output)
|
||||||
|
}
|
||||||
|
if cRegister == 5 {
|
||||||
|
print(String(describing: UnicodeScalar(testMachine.value(for: .E))))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,11 @@ void AllRAMProcessor::set_data_at_address(uint16_t startAddress, size_t length,
|
|||||||
memcpy(&memory_[startAddress], data, endAddress - startAddress);
|
memcpy(&memory_[startAddress], data, endAddress - startAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AllRAMProcessor::get_data_at_address(uint16_t startAddress, size_t length, uint8_t *data) {
|
||||||
|
size_t endAddress = std::min(startAddress + length, (size_t)65536);
|
||||||
|
memcpy(data, &memory_[startAddress], endAddress - startAddress);
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t AllRAMProcessor::get_timestamp() {
|
uint32_t AllRAMProcessor::get_timestamp() {
|
||||||
return timestamp_;
|
return timestamp_;
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ class AllRAMProcessor {
|
|||||||
AllRAMProcessor(size_t memory_size);
|
AllRAMProcessor(size_t memory_size);
|
||||||
uint32_t get_timestamp();
|
uint32_t get_timestamp();
|
||||||
void set_data_at_address(uint16_t startAddress, size_t length, const uint8_t *data);
|
void set_data_at_address(uint16_t startAddress, size_t length, const uint8_t *data);
|
||||||
|
void get_data_at_address(uint16_t startAddress, size_t length, uint8_t *data);
|
||||||
|
|
||||||
class TrapHandler {
|
class TrapHandler {
|
||||||
public:
|
public:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user