Attempt high-level version of Loriciels loader.

This commit is contained in:
Thomas Harte committed 2026-04-27 10:06:30 -04:00
1 parent 6bd497d9d0
commit d8d8d00985
7 files changed
+70 -16

No files matched your search

+1 -1
View File
@@ -893,7 +893,7 @@ public:
// TODO (in the player, not here): adapt it to accept an input clock rate and
// run_for as HalfCycles.
if(!tape_player_is_sleeping_) tape_player_.run_for(cycle.length.get());
if(!tape_player_is_sleeping_) tape_player_.run_for(cycle.length.reduce<Cycles>());
// Pump the AY.
ay_.run_for(cycle.length);
+3 -2
View File
@@ -773,8 +773,9 @@ public:
}
}
if(!tape_player_is_sleeping_)
tape_player_.run_for(cycle.length.as<int>());
if(!tape_player_is_sleeping_) {
tape_player_.run_for(cycle.length.reduce<Cycles>());
}
return addition;
}
+2 -2
View File
@@ -621,7 +621,7 @@ public:
}
private:
void advance(HalfCycles duration) {
void advance(const HalfCycles duration) {
time_since_audio_update_ += duration;
video_ += duration;
@@ -629,7 +629,7 @@ private:
z80_.set_interrupt_line(video_.last_valid()->get_interrupt_line(), video_.last_sequence_point_overrun());
}
if(!tape_player_is_sleeping_) tape_player_.run_for(duration.get());
if(!tape_player_is_sleeping_) tape_player_.run_for(Cycles(duration.get()));
// Update automatic tape motor control, if enabled; if it's been
// 0.5 seconds since software last possibly polled the tape, stop it.
@@ -18,14 +18,14 @@ namespace Thomson::FastLoader {
Sampling code is:
Z35CA LDA ,U ;35CA: A6 C4 '..'
Z35CA LDA ,U ;35CA: A6 C4 '..'
LSRA ;35CC: 44 'D'
STA ,-S ;35CD: A7 E2 '..'
STA ,S ;35CF: A7 E4 '..'
STA ,S ;35CF: A7 E4 '..' ; [S], [S+1] = tape in b6
LDA ,U ;35D1: A6 C4 '..'
LSRA ;35D3: 44 'D'
ADDA ,S ;35D4: AB E4 '..'
STA ,S ;35D6: A7 E4 '..'
STA ,S ;35D6: A7 E4 '..' ; [S] = two-bit tape average in b6:b7
LDA ,U ;35D8: A6 C4 '..'
LSRA ;35DA: 44 'D'
ADDA ,S+ ;35DB: AB E0 '..'
@@ -34,11 +34,26 @@ namespace Thomson::FastLoader {
Outer loop is:
Z35AD BSR Z35CA ;35AD: 8D 1B '..'
BPL Z35AD ;35AF: 2A FC '*.' ; loop until edge?
LDX #M0041 ;35B1: 8E 00 41 '..A'
BSR Z35C4 ;35B4: 8D 0E '..' ; fixed delay
Z35AD BSR Z35CA ;35AD: 8D 1B '..'
BPL Z35AD ;35AF: 2A FC '*.' ; loop until sample differs from 3507
LDX #M0041 ;35B1: 8E 00 41 '..A' ; bit length
BSR Z35C4 ;35B4: 8D 0E '..' ; fixed delay: 7µs + [as per 35C4]
BSR Z35CA ;35B6: 8D 12 '..' ; sample again for bit
BPL Z35BF ;35B8: 2A 05 '*.' ; BPL -> 43 = COMA, which sets carry
COM M3507 ;35BA: 73 35 07 's5.'
CLRA ;35BD: 4F 'O' ; clear carry
BRN Z3603 ;35BE: 21 43 '!C'
ROL M3508 ;35C0: 79 35 08 'y5.'
RTS ;35C3: 39 '9'
Delay loop is:
Z35C4 DEX ;35C4: 30 1F '0.' ; 5 µs
BNE Z35C4 ;35C6: 26 FC '&.' ; 3 µs
CLRA ;35C8: 4F 'O' ; 2 µs
RTS ;35C9: 39 '9' ; 5 µs
i.e. length is 8*X + 7 µs.
*/
struct LoricielsBactron: public Loader {
@@ -60,7 +75,6 @@ struct LoricielsBactron: public Loader {
memory.iterator(address - 2)
)
) {
// TODO: use 'outer' for validation.
switch(address) {
case 0x35cc: return 0x35ad;
default:
@@ -75,7 +89,7 @@ struct LoricielsBactron: public Loader {
const uint16_t address,
MemoryAccess &memory,
CPU::M6809::Registers &,
Storage::Tape::BinaryTapePlayer &,
Storage::Tape::BinaryTapePlayer &player,
Storage::Tape::TapeSerialiser &
) override {
// Check that this is still the expected routine.
@@ -88,9 +102,29 @@ struct LoricielsBactron: public Loader {
return std::make_pair(TrapAction::None, false);
}
// TODO.
player.run_for(Storage::Time(14 + 8*0x41, 1'000'000));
return std::make_pair(TrapAction::None, false);
// Sample current level.
const bool start_level = memory[0x3507] & 0x80;
// Proceed to next edge; time can be skipped here.
while(player.input() == start_level) {
player.complete_pulse();
}
// Wait for 14 + 8*(0x41) µs.
player.run_for(Storage::Time(14 + 8*0x41, 1'000'000));
// Sample current level to determine bit, shift and complement as appropriate.
const bool final_level = player.input();
memory[0x3508] <<= 1;
if(final_level == start_level) {
memory[0x3508] |= 1;
} else {
memory[0x3507] ^= 0xff;
}
return std::make_pair(TrapAction::RTS, true);
}
};
+7
View File
@@ -128,6 +128,8 @@ struct ConcreteMachine:
audio_queue_.lock_flush();
}
uint16_t previous_pc = 0;
template <
CPU::M6809::BusPhase bus_phase,
CPU::M6809::LIC lic,
@@ -250,6 +252,11 @@ struct ConcreteMachine:
value = memory_.read(address);
if constexpr (lic == CPU::M6809::LIC::InstructionFetch) {
if(address == 0x35ad && previous_pc < 0x35ad) {
printf("[%d] 3507: %02x; 3508: %02x\n", tape_player_.serialiser()->offset(), memory_[0x3507], memory_[0x3508]);
}
previous_pc = address;
if(
allow_fast_tape_loading_ &&
tape_player_.motor_control() &&
+10
View File
@@ -132,6 +132,12 @@ void TapePlayer::run_for(const Cycles cycles) {
}
}
void TapePlayer::run_for(const Time time) {
run_for(Cycles(
(get_input_clock_rate() * time.length) / time.clock_rate
));
}
void TapePlayer::run_for_input_pulse() {
jump_to_next_event();
}
@@ -200,6 +206,10 @@ void BinaryTapePlayer::run_for(const Cycles cycles) {
if(motor_is_running_) TapePlayer::run_for(cycles);
}
void BinaryTapePlayer::run_for(const Time time) {
if(motor_is_running_) TapePlayer::run_for(time);
}
void BinaryTapePlayer::set_delegate(Delegate *const delegate) {
delegate_ = delegate;
}
+2
View File
@@ -129,6 +129,7 @@ public:
TapeSerialiser *serialiser();
void run_for(Cycles);
void run_for(Time); // Converts the Time to an integral number of cycles; some precision is lost.
void run_for_input_pulse();
ClockingHint::Preference preferred_clocking() const override;
@@ -166,6 +167,7 @@ public:
bool input() const;
void run_for(Cycles);
void run_for(Time); // Converts the Time to an integral number of cycles; some precision is lost.
struct Delegate {
virtual void tape_did_change_input(BinaryTapePlayer &) = 0;