diff options
author | fulivi <fulivi@users.noreply.github.com> | 2019-09-09 22:05:41 +0200 |
---|---|---|
committer | R. Belmont <rb6502@users.noreply.github.com> | 2019-09-09 16:05:41 -0400 |
commit | d4e2fbd306bf9f847fed16b9a9112eb6d8f56c8e (patch) | |
tree | b91e639bf1dce0eb05d0b813c22f81aa88686da1 /src/lib/formats | |
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')
-rw-r--r-- | src/lib/formats/hti_tape.cpp | 118 | ||||
-rw-r--r-- | src/lib/formats/hti_tape.h | 20 |
2 files changed, 126 insertions, 12 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); } } } diff --git a/src/lib/formats/hti_tape.h b/src/lib/formats/hti_tape.h index 93a8cbac43e..72eb85d55cc 100644 --- a/src/lib/formats/hti_tape.h +++ b/src/lib/formats/hti_tape.h @@ -4,8 +4,8 @@ "HTI" format - Format of images of DC-100 tape cassettes as used in HP 9845 - and HP 85 systems. + Format of images of DC-100 tape cassettes as used in HP 9825, + HP 9845 and HP 85 systems. *********************************************************************/ #ifndef MAME_FORMATS_HTI_TAPE_H @@ -49,10 +49,16 @@ public: // Iterator to access words on tape typedef tape_track_t::iterator track_iterator_t; + // Set no. of bits per word (needed when loading old format) + void set_bits_per_word(unsigned bits) { m_bits_per_word = bits; } + bool load_tape(io_generic *io); void save_tape(io_generic *io); void clear_tape(); + // Return physical length of a bit on tape + static constexpr tape_pos_t bit_length(bool bit) { return bit ? ONE_BIT_LEN : ZERO_BIT_LEN; } + // Return physical length of a 16-bit word on tape static tape_pos_t word_length(tape_word_t w); @@ -84,14 +90,22 @@ public: // Advance an iterator to next word of data adv_res_t adv_it(unsigned track_no , bool forward , track_iterator_t& it); + // Sync with the preamble of a record + bool sync_with_record(unsigned track_no , track_iterator_t& it , unsigned& bit_idx); + + // Get a data word from record, after syncing + adv_res_t next_word(unsigned track_no , track_iterator_t& it , unsigned& bit_idx , tape_word_t& word); + // Scan for beginning of next gap in a given direction bool next_gap(unsigned track_no , tape_pos_t& pos , bool forward , tape_pos_t min_gap); private: // Content of tape tracks tape_track_t m_tracks[ 2 ]; + // Bits per word in old format + unsigned m_bits_per_word; - static bool load_track(io_generic *io , uint64_t& offset , tape_track_t& track); + bool load_track(io_generic *io , uint64_t& offset , tape_track_t& track , bool old_format); static void dump_sequence(io_generic *io , uint64_t& offset , tape_track_t::const_iterator it_start , unsigned n_words); static tape_pos_t word_end_pos(const track_iterator_t& it); |