diff options
author | 2019-09-09 22:05:41 +0200 | |
---|---|---|
committer | 2019-09-09 16:05:41 -0400 | |
commit | d4e2fbd306bf9f847fed16b9a9112eb6d8f56c8e (patch) | |
tree | b91e639bf1dce0eb05d0b813c22f81aa88686da1 /src/lib/formats/hti_tape.cpp | |
parent | eaae4640aa5b9db02ee3e7e16617c8413fe43daf (diff) |
HP9845: TACO driver re-written (#5601)
* hp9825: fixed a bug in 9825t
* hp9845: TACO driver re-written from scratch, DC100 tape separated into
a new device, various adaptations
* hp9845: "new TACO" renamed to just "TACO"
Diffstat (limited to 'src/lib/formats/hti_tape.cpp')
-rw-r--r-- | src/lib/formats/hti_tape.cpp | 118 |
1 files changed, 109 insertions, 9 deletions
diff --git a/src/lib/formats/hti_tape.cpp b/src/lib/formats/hti_tape.cpp index 64fec17ec08..29bab6cd51c 100644 --- a/src/lib/formats/hti_tape.cpp +++ b/src/lib/formats/hti_tape.cpp @@ -11,7 +11,8 @@ #include "imageutl.h" -static constexpr uint32_t FILE_MAGIC = 0x5441434f; // Magic value at start of image file: "TACO" +static constexpr uint32_t OLD_FILE_MAGIC = 0x5441434f; // Magic value at start of old-format image file: "TACO" +static constexpr uint32_t FILE_MAGIC = 0x48544930; // Magic value at start of image file: "HTI0" // *** Position of tape holes *** // At beginning of tape: @@ -40,6 +41,7 @@ static const hti_format_t::tape_pos_t tape_holes[] = { }; hti_format_t::hti_format_t() + : m_bits_per_word(16) { clear_tape(); } @@ -49,14 +51,15 @@ bool hti_format_t::load_tape(io_generic *io) uint8_t tmp[ 4 ]; io_generic_read(io, tmp, 0, 4); - if (pick_integer_be(tmp , 0 , 4) != FILE_MAGIC) { + auto magic = pick_integer_be(tmp , 0 , 4); + if (magic != FILE_MAGIC && magic != OLD_FILE_MAGIC) { return false; } uint64_t offset = 4; for (tape_track_t& track : m_tracks) { - if (!load_track(io , offset , track)) { + if (!load_track(io , offset , track , magic == OLD_FILE_MAGIC)) { clear_tape(); return false; } @@ -114,7 +117,7 @@ hti_format_t::tape_pos_t hti_format_t::word_length(tape_word_t w) zeros = 16 - ones; - return zeros * ZERO_BIT_LEN + (ones + 1) * ONE_BIT_LEN; + return zeros * ZERO_BIT_LEN + ones * ONE_BIT_LEN; } hti_format_t::tape_pos_t hti_format_t::farthest_end(const track_iterator_t& it , bool forward) @@ -187,7 +190,7 @@ void hti_format_t::write_word(unsigned track_no , tape_pos_t start , tape_word_t // as the record expands & contracts when re-written with different content. // Without this fix, a gap could form in the slack big enough to cause // false gap detections. - if (forward && it_high != track.end() && (it_high->first - end_pos) >= (ZERO_BIT_LEN * 16 + ONE_BIT_LEN)) { + if (forward && it_high != track.end() && (it_high->first - end_pos) >= (ZERO_BIT_LEN * 16)) { track.insert(it_high, std::make_pair(end_pos, 0)); it_high--; } @@ -264,6 +267,50 @@ hti_format_t::adv_res_t hti_format_t::adv_it(unsigned track_no , bool forward , } } +bool hti_format_t::sync_with_record(unsigned track_no , track_iterator_t& it , unsigned& bit_idx) +{ + while ((it->second & (1U << bit_idx)) == 0) { + if (bit_idx) { + bit_idx--; + } else { + bit_idx = 15; + auto res = adv_it(track_no, true, it); + if (res != ADV_CONT_DATA) { + return false; + } + } + } + if (bit_idx) { + bit_idx--; + } else { + bit_idx = 15; + } + return true; +} + +hti_format_t::adv_res_t hti_format_t::next_word(unsigned track_no , track_iterator_t& it , unsigned& bit_idx , tape_word_t& word) +{ + if (bit_idx == 15) { + auto res = adv_it(track_no, true, it); + if (res == ADV_NO_MORE_DATA) { + return res; + } + word = it->second; + return res; + } else { + word = it->second << (15 - bit_idx); + auto res = adv_it(track_no, true, it); + if (res == ADV_DISCONT_DATA) { + bit_idx = 15; + it--; + } else if (res == ADV_CONT_DATA) { + word |= (it->second >> (bit_idx + 1)); + } + + return res; + } +} + bool hti_format_t::next_gap(unsigned track_no , tape_pos_t& pos , bool forward , tape_pos_t min_gap) { tape_track_t::iterator it; @@ -323,10 +370,12 @@ bool hti_format_t::next_gap(unsigned track_no , tape_pos_t& pos , bool forward , return n_gaps == 0; } -bool hti_format_t::load_track(io_generic *io , uint64_t& offset , tape_track_t& track) +bool hti_format_t::load_track(io_generic *io , uint64_t& offset , tape_track_t& track , bool old_format) { uint8_t tmp[ 4 ]; uint32_t tmp32; + tape_pos_t delta_pos = 0; + tape_pos_t last_word_end = 0; track.clear(); @@ -350,7 +399,10 @@ bool hti_format_t::load_track(io_generic *io , uint64_t& offset , tape_track_t& tmp32 = pick_integer_le(tmp, 0, 4); - tape_pos_t pos = (tape_pos_t)tmp32; + tape_pos_t pos = (tape_pos_t)tmp32 + delta_pos; + + tape_word_t word_accum = 0; + unsigned bits_in_accum = 0; for (unsigned i = 0; i < n_words; i++) { uint16_t tmp16; @@ -359,8 +411,56 @@ bool hti_format_t::load_track(io_generic *io , uint64_t& offset , tape_track_t& offset += 2; tmp16 = pick_integer_le(tmp, 0, 2); - track.insert(std::make_pair(pos , tmp16)); - pos += word_length(tmp16); + if (!old_format) { + track.insert(std::make_pair(pos , tmp16)); + pos += word_length(tmp16); + } else if (m_bits_per_word == 16) { + // Convert HP9845 & HP85 old format + // Basically, in old format each word had 17 bits (an implicit 1 + // was added at the end). In new format we just keep the 16 bits + // and don't add the 17th bit. + if (i == 0 && tmp16 == 0 && (pos - last_word_end) > 16384) { + // This mysterious heuristic is meant to turn the first + // word of a record into a proper preamble word (from 0 to 1) + // provided this is actually at the beginning of a new record + // (enough distance from end of last record) + tmp16 = 1; + } + track.insert(std::make_pair(pos, tmp16)); + pos += word_length(tmp16); + last_word_end = pos; + delta_pos -= ONE_BIT_LEN; + } else { + // Convert HP9825 old format + // In moving from old to new format we make the 17th bit at the + // end of each word explicit + word_accum |= (tmp16 >> bits_in_accum); + // Avoid storing overlapping words + if (pos >= last_word_end) { + track.insert(std::make_pair(pos, word_accum)); + } + pos += word_length(word_accum); + last_word_end = pos; + if (bits_in_accum == 0) { + word_accum = 0; + } else { + word_accum = tmp16 << (16 - bits_in_accum); + } + word_accum |= (1U << (15 - bits_in_accum)); + if (++bits_in_accum >= 16) { + track.insert(std::make_pair(pos, word_accum)); + pos += word_length(word_accum); + last_word_end = pos; + word_accum = 0; + bits_in_accum = 0; + } + } + } + if (bits_in_accum) { + track.insert(std::make_pair(pos, word_accum)); + tape_pos_t shift = (tape_pos_t)(16 - bits_in_accum) * ZERO_BIT_LEN; + delta_pos += shift; + last_word_end = pos + word_length(word_accum); } } } |