1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-16 19:08:08 +00:00

Attempts to pull reimplementations of TAPION and TAPIN better into line with originals.

Also improves whole flow of the fast tape hack that uses them.
This commit is contained in:
Thomas Harte 2017-12-28 22:48:04 -05:00
parent 11b73a9c0b
commit 5fd0a2b9ea
2 changed files with 54 additions and 17 deletions

View File

@ -181,26 +181,53 @@ class ConcreteMachine:
case CPU::Z80::PartialMachineCycle::ReadOpcode:
if(address == 0x1a63) {
// TAPION
tape_player_.set_motor_control(true);
// Enable the tape motor.
i8255_.set_register(0xab, 0x8);
// Disable interrupts.
z80_.set_value_of_register(CPU::Z80::Register::IFF1, 0);
z80_.set_value_of_register(CPU::Z80::Register::IFF2, 0);
// Use the parser to find a header, and if one is found then populate
// LOWLIM and WINWID, and reset carry. Otherwise set carry.
using Parser = Storage::Tape::MSX::Parser;
std::unique_ptr<Parser::FileSpeed> new_speed = Parser::find_header(tape_player_);
ram_[0xFCA4] = new_speed->minimum_start_bit_duration;
ram_[0xFCA5] = new_speed->low_high_disrimination_duration;
if(new_speed) {
ram_[0xfca4] = new_speed->minimum_start_bit_duration;
ram_[0xfca5] = new_speed->low_high_disrimination_duration;
z80_.set_value_of_register(CPU::Z80::Register::Flags, 0);
} else {
z80_.set_value_of_register(CPU::Z80::Register::Flags, 1);
}
// RET.
*cycle.value = 0xc9;
break;
}
if(address == 0x1abc) {
// TAPIN
// Grab the current values of LOWLIM and WINWID.
using Parser = Storage::Tape::MSX::Parser;
Parser::FileSpeed tape_speed;
tape_speed.minimum_start_bit_duration = ram_[0xFCA4];
tape_speed.low_high_disrimination_duration = ram_[0xFCA5];
// printf("Low lim: %02x / win wid: %02x\n", ram_[0xFCA4], ram_[0xFCA5]);
int next_byte = Parser::get_byte(tape_speed, tape_player_);
z80_.set_value_of_register(CPU::Z80::Register::A, static_cast<uint16_t>(next_byte));
tape_speed.minimum_start_bit_duration = ram_[0xfca4];
tape_speed.low_high_disrimination_duration = ram_[0xfca5];
// Ask the tape parser to grab a byte.
int next_byte = Parser::get_byte(tape_speed, tape_player_);
// If a byte was found, return it with carry unset. Otherwise set carry to
// indicate error.
if(next_byte >= 0) {
z80_.set_value_of_register(CPU::Z80::Register::A, static_cast<uint16_t>(next_byte));
z80_.set_value_of_register(CPU::Z80::Register::Flags, 0);
} else {
z80_.set_value_of_register(CPU::Z80::Register::Flags, 1);
}
// RET.
*cycle.value = 0xc9;
break;
}

View File

@ -69,11 +69,11 @@ std::unique_ptr<Parser::FileSpeed> Parser::find_header(Storage::Tape::BinaryTape
*/
total_length = total_length / 256.0f; // To get the average, in microseconds.
// To convert to the loop count format used by the MSX BIOS.
uint8_t int_result = static_cast<uint8_t>(total_length / (0.00001145f * 1.5f));
uint8_t int_result = static_cast<uint8_t>(total_length / (0.00001145f * 0.75f));
std::unique_ptr<FileSpeed> result(new FileSpeed);
result->minimum_start_bit_duration = int_result + ((int_result + 1) >> 1);
result->low_high_disrimination_duration = int_result;
result->minimum_start_bit_duration = int_result;
result->low_high_disrimination_duration = (int_result * 3) >> 2;
return result;
}
@ -99,19 +99,27 @@ int Parser::get_byte(const FileSpeed &speed, Storage::Tape::BinaryTapePlayer &ta
*/
float minimum_start_bit_duration = static_cast<float>(speed.minimum_start_bit_duration) * 0.00001145f;
while(!tape_player.get_tape()->is_at_end()) {
while(!tape_player.get_tape()->is_at_end() && !tape_player.get_input()) {
// Find a negative transition.
while(!tape_player.get_tape()->is_at_end() && tape_player.get_input()) {
tape_player.run_for_input_pulse();
}
bool level = true;
// Measure the following cycle (i.e. two transitions).
bool level = tape_player.get_input();
float time_to_transition = 0.0f;
int transitions = 0;
while(!tape_player.get_tape()->is_at_end()) {
time_to_transition += static_cast<float>(tape_player.get_cycles_until_next_event()) / static_cast<float>(tape_player.get_input_clock_rate());
tape_player.run_for_input_pulse();
if(level != tape_player.get_input())
break;
if(level != tape_player.get_input()) {
level = tape_player.get_input();
transitions++;
if(transitions == 2)
break;
}
}
// Check length against 'LOWLIM' (i.e. the minimum start bit duration).
if(time_to_transition > minimum_start_bit_duration) {
break;
}
@ -125,10 +133,10 @@ int Parser::get_byte(const FileSpeed &speed, Storage::Tape::BinaryTapePlayer &ta
*/
int result = 0;
const int cycles_per_window = static_cast<int>(
0.5f +
static_cast<float>(speed.low_high_disrimination_duration) *
0.0000173f *
static_cast<float>(tape_player.get_input_clock_rate()) *
2.0f
static_cast<float>(tape_player.get_input_clock_rate())
);
int bits_left = 8;
bool level = tape_player.get_input();
@ -139,8 +147,10 @@ int Parser::get_byte(const FileSpeed &speed, Storage::Tape::BinaryTapePlayer &ta
while(!tape_player.get_tape()->is_at_end() && cycles_remaining) {
const int cycles_until_next_event = static_cast<int>(tape_player.get_cycles_until_next_event());
const int cycles_to_run_for = std::min(cycles_until_next_event, cycles_remaining);
cycles_remaining -= cycles_to_run_for;
tape_player.run_for(Cycles(cycles_to_run_for));
if(level != tape_player.get_input()) {
level = tape_player.get_input();
transitions++;