1
0
mirror of https://github.com/TomHarte/CLK.git synced 2026-04-21 02:17:08 +00:00

Eject zero-cost execution in favour of faulty HLE.

This commit is contained in:
Thomas Harte
2025-01-21 16:45:05 -05:00
parent 348a593dc1
commit 11190cff1d
+324 -124
View File
@@ -235,6 +235,9 @@ public:
audio_queue_.flush();
}
// HACK. NOCOMMIT.
int pulse_num_ = 0;
Cycles perform_bus_operation(
const CPU::MOS6502::BusOperation operation,
const uint16_t address,
@@ -250,17 +253,15 @@ public:
timers_.tick(timers_cycles.as<int>());
tape_player_->run_for(length);
if(!is_fast_loading_) {
video_.run_for(length);
video_.run_for(length);
if(c1541_) {
c1541_cycles_ += length * Cycles(1'000'000);
c1541_->run_for(c1541_cycles_.divide(media_divider_));
}
time_since_audio_update_ += length;
if(c1541_) {
c1541_cycles_ += length * Cycles(1'000'000);
c1541_->run_for(c1541_cycles_.divide(media_divider_));
}
time_since_audio_update_ += length;
if(operation == CPU::MOS6502::BusOperation::Ready) {
return length;
}
@@ -304,122 +305,33 @@ public:
serial_port_.set_output(Serial::Line::Attention, Serial::LineLevel(~output & 0x04));
}
} else if(address < 0xfd00 || address >= 0xff40) {
// if(use_fast_tape_hack_ && operation == CPU::MOS6502Esque::BusOperation::ReadOpcode && address == 0xe5fd) {
// ++pulse_num;
// const bool is_interesting = pulse_num >= 15220;
//
// if(pulse_num == 15224) {
// printf("");
// }
//
//// if(address == 0xe68a) {
//// }
//
// if(address == 0xe5fd) {
// // TODO:
// //
// // ; read a dipole from tape (and then RTS)
// // ;
// // ; if c=1 then error
// // ; else if v=1 then short
// // ; else if n=0 then long
// // ; else word
// // ; end
// // ; end
// // ; end
//
// // 76 = V, not N or C
// // b7 = N
//
// // Compare with:
// //
// // dsamp1 *=*+2 ;time constant for x cell sample 07B8
// // dsamp2 *=*+2 ;time constant for y cell sample
// // zcell *=*+2 ;time constant for z cell verify
//
// const auto read16 = [&](uint16_t address) {
// // These constants are defined in terms of the timer clocks; convert them to
// // fractions of a second.
// const auto constant = uint16_t( map_.read(address) | (map_.read(address + 1) << 8) );
// return (float(constant) * video_.timer_cycle_length().as<float>()) / float(get_clock_rate());
// };
// const auto dsamp1 = read16(0x7b8);
// const auto dsamp2 = read16(0x7ba);
// const auto zcell = read16(0x7bc);
// using Pulse = Storage::Tape::Pulse;
//
// // Wait until tape input is high (i.e. input is low).
//// while(tape_player_->current_pulse().type != Pulse::Type::Low) {
//// tape_player_->complete_pulse();
//// }
//
// // Wait until tape input is low.
// while(tape_player_->current_pulse().type != Pulse::Type::High) {
// tape_player_->complete_pulse();
// }
//
// // Count time of low high, and classify.
// const auto length1 = tape_player_->current_pulse().length.get<float>();
// tape_player_->complete_pulse(); // Consume High.
// const auto length2 = tape_player_->current_pulse().length.get<float>();
// tape_player_->complete_pulse(); // Consume Low.
//
// uint8_t flags =
// uint8_t(m6502_.value_of(CPU::MOS6502::Register::Flags)) &
// ~(CPU::MOS6502::Flag::Carry | CPU::MOS6502::Flag::Overflow | CPU::MOS6502::Flag::Sign);
//
// if(std::abs(length1 - length2) > 0.00025f) {
// // Lengths are too dissimilar; call that an error.
// flags |= CPU::MOS6502::Flag::Carry;
// }
//
//// const auto dsamp1_difference = std::abs(length1 - dsamp1);
//// const auto dsamp2_difference = std::abs(length1 - dsamp2);
//// const auto zcell_difference = std::abs(length1 - zcell);
//
// if(length2 < dsamp1) {
// flags |= CPU::MOS6502::Flag::Overflow;
// } else if(length2 > zcell) {
// flags |= CPU::MOS6502::Flag::Sign;
// }
//
// m6502_.set_value_of(CPU::MOS6502::Register::Flags, flags);
//
// if(is_interesting) {
// logger.info().append("Read: %d %d",
// int(length1 * 1'000'000),
// int(length2 * 1'000'000)
// );
// }
//
// *value = 0x60; // i.e. RTS.
// }
//
// if(is_interesting) {
// const auto flags = m6502_.value_of(CPU::MOS6502::Register::Flags);
// logger.info().append("%d @ %d dipole result: %c%c%c",
// pulse_num,
// tape_player_->event_count(),
// flags & CPU::MOS6502::Flag::Sign ? 'n' : '-',
// flags & CPU::MOS6502::Flag::Overflow ? 'v' : '-',
// flags & CPU::MOS6502::Flag::Carry ? 'c' : '-');
//}
// } else {
constexpr bool use_hle = true;
constexpr uint16_t trap = use_hle ? 0xe5fd : 0xe68a;
if(use_fast_tape_hack_ && operation == CPU::MOS6502Esque::BusOperation::ReadOpcode && address == trap) {
++pulse_num_;
if(use_hle) {
read_dipole();
}
*value = 0x60;
if(!tape_player_->is_at_end()) {
const auto flags = uint8_t(m6502_.value_of(CPU::MOS6502::Register::Flags));
logger.info().append("%d @ %d dipole result: %c%c%c",
pulse_num_,
tape_player_->event_count(),
flags & CPU::MOS6502::Flag::Sign ? 'n' : '-',
flags & CPU::MOS6502::Flag::Overflow ? 'v' : '-',
flags & CPU::MOS6502::Flag::Carry ? 'c' : '-');
}
} else {
if(is_read(operation)) {
*value = map_.read(address);
} else {
map_.write(address) = *value;
}
// If fast loading is enabled, zero-rate anything in the function rddipl, which reads
// dipoles from tape.
if(use_fast_tape_hack_ && operation == CPU::MOS6502Esque::BusOperation::ReadOpcode) {
is_fast_loading_ = (address >= 0xe5fd) && (address <= 0xeb71);
}
// if(is_in_rddipl) {
// return Cycles(0);
// }
// }
}
} else if(address < 0xff00) {
// Miscellaneous hardware. All TODO.
if(is_read(operation)) {
@@ -646,7 +558,7 @@ public:
}
}
return is_fast_loading_ ? Cycles(0) : length;
return length;
}
private:
@@ -705,8 +617,6 @@ private:
return video_.get_display_type();
}
int pulse_num = 0;
void run_for(const Cycles cycles) final {
m6502_.run_for(cycles);
@@ -793,16 +703,306 @@ private:
bool play_button_ = false;
bool allow_fast_tape_hack_ = false; // TODO: implement fast-tape hack.
bool use_fast_tape_hack_ = false;
bool is_fast_loading_ = false;
void set_use_fast_tape() {
use_fast_tape_hack_ = allow_fast_tape_hack_ && tape_player_->motor_control() && rom_is_paged_;
is_fast_loading_ &= use_fast_tape_hack_;
}
void update_tape_motor() {
const auto output = io_output_ | ~io_direction_;
tape_player_->set_motor_control(play_button_ && (~output & 0x08));
set_use_fast_tape();
}
void read_dipole() {
if(pulse_num_ == 15225) {
printf("");
}
// Provides an HLE implementation of the routine beginning at address
// 0xe5fd in the ROM, i.e. rddipl (read dipole) as that's the one that
// spins awaiting changes in tape input.
using Register = CPU::MOS6502::Register;
using Pulse = Storage::Tape::Pulse;
using Flag = CPU::MOS6502::Flag;
auto s = uint8_t(m6502_.value_of(Register::StackPointer));
auto flags = uint8_t(m6502_.value_of(Register::Flags));
const unsigned int timer_clock_rate =
static_cast<unsigned int>(get_clock_rate()) / video_.timer_cycle_length().as<unsigned int>();
//; trigger on negative edge (beginning) of dipole
//;
//rddipl
// ldx dsamp1 ; setup x,y with 1st sample point
// ldy dsamp1+1
//badeg1
// lda dsamp2+1 ; put 2nd samp value on stack in reverse order
// pha
// lda dsamp2
// pha
const auto read16 = [&](uint16_t address) {
return uint16_t( map_.read(address) | (map_.read(address + 1) << 8) );
};
const auto dsamp1 = read16(0x7b8);
const auto dsamp2 = read16(0x7ba);
const auto zcell = read16(0x7bc);
map_.write(0x100 + s) = uint8_t(dsamp2 >> 8);
--s;
map_.write(0x100 + s) = uint8_t (dsamp2);
//
// lda #$10
//rwtl ; wait till rd line is high
// bit port
// beq rwtl ; !ls!
//
const auto wait_for = [&](Pulse::Type type) -> bool {
while(!tape_player_->is_at_end() && tape_player_->current_pulse().type != type) {
tape_player_->complete_pulse();
}
return tape_player_->current_pulse().type == type;
};
if(!wait_for(Pulse::Low)) {
flags |= Flag::Carry;
return;
}
//
//rwth ;it's high...now wait till it's low
// bit port
// bne rwth ; caught the edge
if(!wait_for(Pulse::High)) {
flags |= Flag::Carry;
return;
}
// stx timr2l
// sty timr2h
//
//; go! ...ta
//
// pla ;go! ...ta
// sta timr3l
// pla
// sta timr3h ;go! ...tb
//
//; clear timer flags
//
// lda #$50 ; clr ta,tb
// sta tedirq
//
//; um...check that edge again
//
//casdb1
// lda port
// cmp port
// bne casdb1 ; something is going on here...
// and #$10 ; a look at that edge again
// bne badeg1 ; woa! got a bad edge trigger !ls!
//
//; must have been a valid edge
//;
//; do stop key check here
//
// jsr balout
// lda #$10
//wata ; wait for ta to timeout
// bit port ; kuldge, kludge, kludge !!! <<><>>
// bne rshort ; kuldge, kludge, kludge !!! <<><>>
// bit tedirq
// beq wata
//
//; now do the dipole sample #1
//
//casdb2
// lda port
// cmp port
// bne casdb2
// and #$10
// bne rshort ; shorts anyone?
//
const auto pulse_timer_cycles = [&] {
const auto length = tape_player_->current_pulse().length;
return (length.length * timer_clock_rate) / length.clock_rate;
};
const auto pulse_length = pulse_timer_cycles();
if(pulse_length <= dsamp1) {
// Goto rshort, i.e. ...
flags |= Flag::Overflow;
flags &= ~Flag::Carry;
m6502_.set_value_of(Register::Flags, flags);
return;
}
if(pulse_length <= dsamp2) {
// Goto rlong, i.e. ...
flags &= ~(Flag::Carry | Flag::Sign);
m6502_.set_value_of(Register::Flags, flags);
return;
}
// Test for a word by looking at the second part of the pulse.
tape_player_->complete_pulse();
const auto second_pulse_length = pulse_timer_cycles();
if(second_pulse_length <= zcell) {
flags |= Flag::Sign;
flags &= ~(Flag::Carry | Flag::Overflow);
m6502_.set_value_of(Register::Flags, flags);
return;
}
flags |= Flag::Carry;
m6502_.set_value_of(Register::Flags, flags);
//; perhaps a long or a word?
//
// lda #$40
//watb
// bit tedirq
// beq watb
//
//; wait for tb to timeout
//; now do the dipole sample #2
//
//casdb3
// lda port
// cmp port
// bne casdb3
// and #$10
// bne rlong ; looks like a long from here !ls!
// ; or could it be a word?
// lda zcell
// sta timr2l
// lda zcell+1
// sta timr2h
// ; go! z-cell check
// ; clear ta flag
// lda #$10
// sta tedirq ; verify +180 half of word dipole
// lda #$10
//wata2
// bit tedirq
// beq wata2 ; check z-cell is low
//casdb4
// lda port
// cmp port
// bne casdb4
// and #$10
// beq rderr1 ; !ls!
// bit twordd ; got a word dipole
// bmi dipok ; !bra
//
//rshort
// bit tshrtd ; got a short
// bvs dipok ; !bra
//
//rlong
// bit tlongd ; got a long
//
//dipok
// clc ; everything's fine
// rts
//
//rderr1
// sec ; i'm confused
// rts
// ++pulse_num;
// const bool is_interesting = pulse_num >= 15220;
//
// if(pulse_num == 15224) {
// printf("");
// }
//
//// if(address == 0xe68a) {
//// }
//
// if(address == 0xe5fd) {
// // TODO:
// //
// // ; read a dipole from tape (and then RTS)
// // ;
// // ; if c=1 then error
// // ; else if v=1 then short
// // ; else if n=0 then long
// // ; else word
// // ; end
// // ; end
// // ; end
//
// // 76 = V, not N or C
// // b7 = N
//
// // Compare with:
// //
// // dsamp1 *=*+2 ;time constant for x cell sample 07B8
// // dsamp2 *=*+2 ;time constant for y cell sample
// // zcell *=*+2 ;time constant for z cell verify
//
// const auto zcell = read16(0x7bc);
// using Pulse = Storage::Tape::Pulse;
//
// // Wait until tape input is high (i.e. input is low).
//// while(tape_player_->current_pulse().type != Pulse::Type::Low) {
//// tape_player_->complete_pulse();
//// }
//
// // Wait until tape input is low.
// while(tape_player_->current_pulse().type != Pulse::Type::High) {
// tape_player_->complete_pulse();
// }
//
// // Count time of low high, and classify.
// const auto length1 = tape_player_->current_pulse().length.get<float>();
// tape_player_->complete_pulse(); // Consume High.
// const auto length2 = tape_player_->current_pulse().length.get<float>();
// tape_player_->complete_pulse(); // Consume Low.
//
// uint8_t flags =
// uint8_t(m6502_.value_of(CPU::MOS6502::Register::Flags)) &
// ~(CPU::MOS6502::Flag::Carry | CPU::MOS6502::Flag::Overflow | CPU::MOS6502::Flag::Sign);
//
// if(std::abs(length1 - length2) > 0.00025f) {
// // Lengths are too dissimilar; call that an error.
// flags |= CPU::MOS6502::Flag::Carry;
// }
//
//// const auto dsamp1_difference = std::abs(length1 - dsamp1);
//// const auto dsamp2_difference = std::abs(length1 - dsamp2);
//// const auto zcell_difference = std::abs(length1 - zcell);
//
// if(length2 < dsamp1) {
// flags |= CPU::MOS6502::Flag::Overflow;
// } else if(length2 > zcell) {
// flags |= CPU::MOS6502::Flag::Sign;
// }
//
// m6502_.set_value_of(CPU::MOS6502::Register::Flags, flags);
//
// if(is_interesting) {
// logger.info().append("Read: %d %d",
// int(length1 * 1'000'000),
// int(length2 * 1'000'000)
// );
// }
//
// *value = 0x60; // i.e. RTS.
// }
//
// if(is_interesting) {
// const auto flags = m6502_.value_of(CPU::MOS6502::Register::Flags);
// logger.info().append("%d @ %d dipole result: %c%c%c",
// pulse_num,
// tape_player_->event_count(),
// flags & CPU::MOS6502::Flag::Sign ? 'n' : '-',
// flags & CPU::MOS6502::Flag::Overflow ? 'v' : '-',
// flags & CPU::MOS6502::Flag::Carry ? 'c' : '-');
//}
// } else {
}
uint8_t io_direction_ = 0x00, io_output_ = 0x00;