mirror of
https://github.com/TomHarte/CLK.git
synced 2025-02-02 16:38:51 +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) {
|
||||
CSTestMachineZ80RegisterProgramCounter,
|
||||
CSTestMachineZ80RegisterStackPointer,
|
||||
|
||||
CSTestMachineZ80RegisterC,
|
||||
CSTestMachineZ80RegisterE,
|
||||
CSTestMachineZ80RegisterDE,
|
||||
};
|
||||
|
||||
@class CSTestMachineZ80;
|
||||
|
||||
@interface CSTestMachineTrapHandler
|
||||
@protocol CSTestMachineTrapHandler
|
||||
- (void)testMachine:(CSTestMachineZ80 *)testMachine didTrapAtAddress:(uint16_t)address;
|
||||
@end
|
||||
|
||||
@interface CSTestMachineZ80 : NSObject
|
||||
|
||||
- (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)setValue:(uint16_t)value forRegister:(CSTestMachineZ80Register)reg;
|
||||
|
@ -33,6 +33,9 @@ static CPU::Z80::Register registerForRegister(CSTestMachineZ80Register reg) {
|
||||
switch (reg) {
|
||||
case CSTestMachineZ80RegisterProgramCounter: return CPU::Z80::Register::ProgramCounter;
|
||||
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);
|
||||
}
|
||||
|
||||
- (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 {
|
||||
return _processor.get_value_of_register(registerForRegister(reg));
|
||||
}
|
||||
|
@ -9,21 +9,49 @@
|
||||
import XCTest
|
||||
import Foundation
|
||||
|
||||
class ZexallTests: XCTestCase {
|
||||
class ZexallTests: XCTestCase, CSTestMachineTrapHandler {
|
||||
|
||||
func testZexall() {
|
||||
if let filename = Bundle(for: type(of: self)).path(forResource: "zexall", ofType: "com") {
|
||||
if let testData = try? Data(contentsOf: URL(fileURLWithPath: filename)) {
|
||||
|
||||
// install test program, at the usual CP/M place
|
||||
let machine = CSTestMachineZ80()
|
||||
machine.setData(testData, atAddress: 0x0100)
|
||||
|
||||
machine.setValue(0x0100, for: .programCounter)
|
||||
machine.setValue(0xffff, for: .stackPointer)
|
||||
// add a RET at the CP/M entry location, and establish it as a trap location
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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() {
|
||||
return timestamp_;
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ class AllRAMProcessor {
|
||||
AllRAMProcessor(size_t memory_size);
|
||||
uint32_t get_timestamp();
|
||||
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 {
|
||||
public:
|
||||
|
Loading…
x
Reference in New Issue
Block a user