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:
+324
-124
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user