diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua index f4d9214f320..aac794dddcc 100644 --- a/scripts/target/mame/mess.lua +++ b/scripts/target/mame/mess.lua @@ -2601,6 +2601,8 @@ files { MAME_DIR .. "src/mame/drivers/hp2100.cpp", MAME_DIR .. "src/mame/drivers/hp2620.cpp", MAME_DIR .. "src/mame/drivers/hp700.cpp", + MAME_DIR .. "src/mame/machine/hp2640_tape.cpp", + MAME_DIR .. "src/mame/machine/hp2640_tape.h", MAME_DIR .. "src/mame/drivers/hp2640.cpp", MAME_DIR .. "src/mame/drivers/hp95lx.cpp", MAME_DIR .. "src/mame/drivers/hp9825.cpp", diff --git a/src/devices/machine/1ma6.cpp b/src/devices/machine/1ma6.cpp index 284088a9f00..621e6aa6960 100644 --- a/src/devices/machine/1ma6.cpp +++ b/src/devices/machine/1ma6.cpp @@ -341,7 +341,7 @@ void hp_1ma6_device::device_add_mconfig(machine_config &config) m_tape->set_acceleration(ACCELERATION); m_tape->set_set_points(SLOW_SPEED , FAST_SPEED); m_tape->set_tick_size(TACH_TICK_LEN); - m_tape->set_bits_per_word(16); + m_tape->set_image_format(hti_format_t::HTI_DELTA_MOD_16_BITS); m_tape->set_go_threshold(MOVING_THRESHOLD); m_tape->cart_out().set(FUNC(hp_1ma6_device::cart_out_w)); m_tape->hole().set(FUNC(hp_1ma6_device::hole_w)); diff --git a/src/devices/machine/hp_dc100_tape.cpp b/src/devices/machine/hp_dc100_tape.cpp index a9cbb925163..2c4b55e0156 100644 --- a/src/devices/machine/hp_dc100_tape.cpp +++ b/src/devices/machine/hp_dc100_tape.cpp @@ -84,6 +84,7 @@ hp_dc100_tape_device::hp_dc100_tape_device(const machine_config &mconfig, const , m_motion_handler(*this) , m_rd_bit_handler(*this) , m_wr_bit_handler(*this) + , m_unit_name() , m_image() , m_image_dirty(false) { @@ -128,7 +129,14 @@ std::string hp_dc100_tape_device::call_display() return buffer; } - char track = m_track ? 'B' : 'A'; + if (!m_unit_name.empty()) { + buffer += m_unit_name; + buffer += " "; + } + + if (m_image.no_of_tracks() > 1) { + buffer += m_track ? "B " : "A "; + } char r_w = m_current_op == OP_WRITE || m_current_op == OP_ERASE ? 'W' : 'R'; char m1; char m2; @@ -143,7 +151,7 @@ std::string hp_dc100_tape_device::call_display() int pos_in = get_approx_pos() / hti_format_t::ONE_INCH_POS; - buffer = string_format("%c %c %c%c [%04d/1824]" , track , r_w , m1 , m2 , pos_in); + buffer += string_format("%c %c%c [%04d/1824]" , r_w , m1 , m2 , pos_in); return buffer; } @@ -169,9 +177,9 @@ void hp_dc100_tape_device::set_tick_size(hti_format_t::tape_pos_t size) m_tick_size = size; } -void hp_dc100_tape_device::set_bits_per_word(unsigned bits) +void hp_dc100_tape_device::set_image_format(hti_format_t::image_format_t fmt) { - m_image.set_bits_per_word(bits); + m_image.set_image_format(fmt); } void hp_dc100_tape_device::set_go_threshold(double threshold) @@ -179,9 +187,14 @@ void hp_dc100_tape_device::set_go_threshold(double threshold) m_go_threshold = threshold; } +void hp_dc100_tape_device::set_name(const std::string& name) +{ + m_unit_name = name; +} + void hp_dc100_tape_device::set_track_no(unsigned track) { - if (m_track != track) { + if (m_track != track && track < m_image.no_of_tracks()) { LOG_DBG("Setting track %u (op=%d)\n" , track , static_cast(m_current_op)); auto saved_op = m_current_op; if (m_current_op != OP_IDLE) { @@ -434,7 +447,7 @@ void hp_dc100_tape_device::time_to_next_gap(hti_format_t::tape_pos_t min_gap_siz hti_format_t::track_iterator_t it; found = m_image.next_data(get_track_no() , tmp , fwd , true , it); if (found) { - tmp = hti_format_t::farthest_end(it , !fwd); + tmp = m_image.farthest_end(it , !fwd); } } if (found && m_image.next_gap(get_track_no() , tmp , fwd , min_gap_size)) { @@ -875,7 +888,7 @@ void hp_dc100_tape_device::load_rd_word() m_bit_idx = 0; } // This is actually the nearest end (dir is inverted) - m_rw_pos = m_next_bit_pos = hti_format_t::farthest_end(m_rd_it , !fwd); + m_rw_pos = m_next_bit_pos = m_image.farthest_end(m_rd_it , !fwd); // Compute end of bit cell hti_format_t::tape_pos_t bit_len = m_image.bit_length(BIT(m_rd_it->second , m_bit_idx)); if (!fwd) { diff --git a/src/devices/machine/hp_dc100_tape.h b/src/devices/machine/hp_dc100_tape.h index 167bb953b10..2d3a2ea0617 100644 --- a/src/devices/machine/hp_dc100_tape.h +++ b/src/devices/machine/hp_dc100_tape.h @@ -44,8 +44,9 @@ public: void set_acceleration(double accel); void set_set_points(double slow_sp , double fast_sp); void set_tick_size(hti_format_t::tape_pos_t size); - void set_bits_per_word(unsigned bits); + void set_image_format(hti_format_t::image_format_t fmt); void set_go_threshold(double threshold); + void set_name(const std::string& name); // Commands void set_track_no(unsigned track); @@ -123,6 +124,7 @@ private: double m_fast_set_point; hti_format_t::tape_pos_t m_tick_size; double m_go_threshold; + std::string m_unit_name; // State hti_format_t::tape_pos_t m_tape_pos; diff --git a/src/devices/machine/hp_taco.cpp b/src/devices/machine/hp_taco.cpp index 6760a7eda01..64e1cd9588c 100644 --- a/src/devices/machine/hp_taco.cpp +++ b/src/devices/machine/hp_taco.cpp @@ -293,6 +293,11 @@ hp_taco_device::hp_taco_device(const machine_config &mconfig, const char *tag, d { } +void hp_taco_device::set_name(const std::string& name) +{ + m_tape->set_name(name); +} + void hp_taco_device::reg_w(offs_t offset, uint16_t data) { LOG_REG("wr R%u = %04x\n", 4 + offset , data); @@ -538,7 +543,7 @@ void hp_taco_device::device_add_mconfig(machine_config &config) m_tape->set_acceleration(ACCELERATION); m_tape->set_set_points(SLOW_SPEED , FAST_SPEED); m_tape->set_tick_size(TACH_TICK_LEN); - m_tape->set_bits_per_word(16); + m_tape->set_image_format(hti_format_t::HTI_DELTA_MOD_16_BITS); m_tape->set_go_threshold(MOVING_THRESHOLD); m_tape->cart_out().set(FUNC(hp_taco_device::cart_out_w)); m_tape->hole().set(FUNC(hp_taco_device::hole_w)); diff --git a/src/devices/machine/hp_taco.h b/src/devices/machine/hp_taco.h index 0ea70122b7f..243b79e98ba 100644 --- a/src/devices/machine/hp_taco.h +++ b/src/devices/machine/hp_taco.h @@ -27,6 +27,9 @@ public: auto flg() { return m_flg_handler.bind(); } auto sts() { return m_sts_handler.bind(); } + // Set unit name + void set_name(const std::string& name); + // Register read/write void reg_w(offs_t offset, uint16_t data); uint16_t reg_r(offs_t offset); diff --git a/src/lib/formats/hti_tape.cpp b/src/lib/formats/hti_tape.cpp index 29bab6cd51c..7f77e3f99df 100644 --- a/src/lib/formats/hti_tape.cpp +++ b/src/lib/formats/hti_tape.cpp @@ -12,7 +12,8 @@ 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" +static constexpr uint32_t FILE_MAGIC_DELTA = 0x48544930; // Magic value at start of delta-modulation image file: "HTI0" +static constexpr uint32_t FILE_MAGIC_MANCHESTER = 0x48544931; // Magic value at start of manchester-modulation image file: "HTI1" // *** Position of tape holes *** // At beginning of tape: @@ -41,7 +42,7 @@ static const hti_format_t::tape_pos_t tape_holes[] = { }; hti_format_t::hti_format_t() - : m_bits_per_word(16) + : m_img_format(HTI_DELTA_MOD_16_BITS) { clear_tape(); } @@ -52,13 +53,15 @@ bool hti_format_t::load_tape(io_generic *io) io_generic_read(io, tmp, 0, 4); auto magic = pick_integer_be(tmp , 0 , 4); - if (magic != FILE_MAGIC && magic != OLD_FILE_MAGIC) { + if (((m_img_format == HTI_DELTA_MOD_16_BITS || m_img_format == HTI_DELTA_MOD_17_BITS) && magic != FILE_MAGIC_DELTA && magic != OLD_FILE_MAGIC) || + (m_img_format == HTI_MANCHESTER_MOD && magic != FILE_MAGIC_MANCHESTER)) { return false; } uint64_t offset = 4; - for (tape_track_t& track : m_tracks) { + for (unsigned i = 0; i < no_of_tracks(); i++) { + tape_track_t& track = m_tracks[ i ]; if (!load_track(io , offset , track , magic == OLD_FILE_MAGIC)) { clear_tape(); return false; @@ -72,12 +75,13 @@ void hti_format_t::save_tape(io_generic *io) { uint8_t tmp[ 4 ]; - place_integer_be(tmp, 0, 4, FILE_MAGIC); + place_integer_be(tmp, 0, 4, m_img_format == HTI_MANCHESTER_MOD ? FILE_MAGIC_MANCHESTER : FILE_MAGIC_DELTA); io_generic_write(io, tmp, 0, 4); uint64_t offset = 4; - for (const tape_track_t& track : m_tracks) { + for (unsigned i = 0; i < no_of_tracks(); i++) { + const tape_track_t& track = m_tracks[ i ]; tape_pos_t next_pos = (tape_pos_t)-1; unsigned n_words = 0; tape_track_t::const_iterator it_start; @@ -105,7 +109,7 @@ void hti_format_t::clear_tape() } } -hti_format_t::tape_pos_t hti_format_t::word_length(tape_word_t w) +hti_format_t::tape_pos_t hti_format_t::word_length(tape_word_t w) const { unsigned zeros , ones; @@ -117,10 +121,10 @@ hti_format_t::tape_pos_t hti_format_t::word_length(tape_word_t w) zeros = 16 - ones; - return zeros * ZERO_BIT_LEN + ones * ONE_BIT_LEN; + return zeros * bit_length(false) + ones * bit_length(true); } -hti_format_t::tape_pos_t hti_format_t::farthest_end(const track_iterator_t& it , bool forward) +hti_format_t::tape_pos_t hti_format_t::farthest_end(const track_iterator_t& it , bool forward) const { if (forward) { return word_end_pos(it); @@ -190,7 +194,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)) { + if (forward && it_high != track.end() && (it_high->first - end_pos) >= (bit_length(false) * 16)) { track.insert(it_high, std::make_pair(end_pos, 0)); it_high--; } @@ -414,7 +418,7 @@ bool hti_format_t::load_track(io_generic *io , uint64_t& offset , tape_track_t& if (!old_format) { track.insert(std::make_pair(pos , tmp16)); pos += word_length(tmp16); - } else if (m_bits_per_word == 16) { + } else if (m_img_format == HTI_DELTA_MOD_16_BITS) { // 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 @@ -429,7 +433,7 @@ bool hti_format_t::load_track(io_generic *io , uint64_t& offset , tape_track_t& track.insert(std::make_pair(pos, tmp16)); pos += word_length(tmp16); last_word_end = pos; - delta_pos -= ONE_BIT_LEN; + delta_pos -= DELTA_ONE_BIT_LEN; } else { // Convert HP9825 old format // In moving from old to new format we make the 17th bit at the @@ -458,7 +462,7 @@ bool hti_format_t::load_track(io_generic *io , uint64_t& offset , tape_track_t& } 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; + tape_pos_t shift = (tape_pos_t)(16 - bits_in_accum) * DELTA_ZERO_BIT_LEN; delta_pos += shift; last_word_end = pos + word_length(word_accum); } @@ -483,12 +487,12 @@ void hti_format_t::dump_sequence(io_generic *io , uint64_t& offset , tape_track_ } } -hti_format_t::tape_pos_t hti_format_t::word_end_pos(const track_iterator_t& it) +hti_format_t::tape_pos_t hti_format_t::word_end_pos(const track_iterator_t& it) const { return it->first + word_length(it->second); } -void hti_format_t::adjust_it(tape_track_t& track , track_iterator_t& it , tape_pos_t pos) +void hti_format_t::adjust_it(tape_track_t& track , track_iterator_t& it , tape_pos_t pos) const { if (it != track.begin()) { --it; diff --git a/src/lib/formats/hti_tape.h b/src/lib/formats/hti_tape.h index 72eb85d55cc..7725b87fa2a 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 9825, - HP 9845 and HP 85 systems. + Format of images of DC-100 tape cassettes as used in HP 264x, + HP 9825, HP 9845 and HP 85 systems. *********************************************************************/ #ifndef MAME_FORMATS_HTI_TAPE_H @@ -34,11 +34,15 @@ public: // Tape length: 140 ft of usable tape + 72" of punched tape at either end static constexpr tape_pos_t TAPE_LENGTH = (140 * 12 + 72 * 2) * ONE_INCH_POS; + // Length of bits in delta modulation // Length of 0 bits at slow tape speed: 1/(35200 Hz) - static constexpr tape_pos_t ZERO_BIT_LEN = 619; - + static constexpr tape_pos_t DELTA_ZERO_BIT_LEN = 619; // Length of 1 bits at slow tape speed: 1.75 times ZERO_BIT_LEN - static constexpr tape_pos_t ONE_BIT_LEN = 1083; + static constexpr tape_pos_t DELTA_ONE_BIT_LEN = 1083; + // Length of bits in Manchester modulation + // By "bits" here we mean each of the halves of data bit cells + // Zeros & ones have same length + static constexpr tape_pos_t MANCHESTER_BIT_LEN = 621; // Words stored on tape typedef uint16_t tape_word_t; @@ -49,20 +53,38 @@ 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; } + // Set image format + enum image_format_t { + // Delta modulation, 16 bits per word, 2 tracks per cartridge + // HP 9845 & HP 85 + HTI_DELTA_MOD_16_BITS, + // Delta modulation, 17 bits per word, 2 tracks per cartridge + // HP 9825 + HTI_DELTA_MOD_17_BITS, + // Manchester modulation, 1 track per cartridge + // HP 264x + HTI_MANCHESTER_MOD + }; + + void set_image_format(image_format_t fmt) { m_img_format = fmt; } + + // Return number of tracks + unsigned no_of_tracks() const { return m_img_format == HTI_MANCHESTER_MOD ? 1 : 2; } 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; } + tape_pos_t bit_length(bool bit) const + { + return m_img_format == HTI_MANCHESTER_MOD ? MANCHESTER_BIT_LEN : (bit ? DELTA_ONE_BIT_LEN : DELTA_ZERO_BIT_LEN); + } // Return physical length of a 16-bit word on tape - static tape_pos_t word_length(tape_word_t w); + tape_pos_t word_length(tape_word_t w) const; - static tape_pos_t farthest_end(const track_iterator_t& it , bool forward); + tape_pos_t farthest_end(const track_iterator_t& it , bool forward) const; static bool pos_offset(tape_pos_t& pos , bool forward , tape_pos_t offset); @@ -102,14 +124,14 @@ public: private: // Content of tape tracks tape_track_t m_tracks[ 2 ]; - // Bits per word in old format - unsigned m_bits_per_word; + // Image format + image_format_t m_img_format; 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); - static void adjust_it(tape_track_t& track , track_iterator_t& it , tape_pos_t pos); + tape_pos_t word_end_pos(const track_iterator_t& it) const; + void adjust_it(tape_track_t& track , track_iterator_t& it , tape_pos_t pos) const; static void ensure_a_lt_b(tape_pos_t& a , tape_pos_t& b); }; diff --git a/src/mame/drivers/hp2640.cpp b/src/mame/drivers/hp2640.cpp index 13dba354de9..a33f75820b8 100644 --- a/src/mame/drivers/hp2640.cpp +++ b/src/mame/drivers/hp2640.cpp @@ -23,10 +23,10 @@ // was used with APL\3000 on the HP 3000 Series II/III computers from 1976 // into the 1980s. I recently got APL\3000 running under simulation so this // is an attempt to recreate the whole experience with the APL characters -// on the terminal device designed for it. The HP2641A is basically a 2641 -// with a few altered ROMs (many are identical to the 2641) and one +// on the terminal device designed for it. The HP2641A is basically a 2645 +// with a few altered ROMs (many are identical to the 2645) and one // additional 2K ROM for which a second CTL PCA was required that was not -// needed in the 2641. +// needed in the 2645. // // This driver emulates the HP2641A model, as composed of the following cards: // - 02640-60123 Keyboard interface @@ -39,6 +39,8 @@ // - 02640-60192 Second CTL PCA with one additional 2K ROM and 256b SRAM. // - 02640-60065 4k DRAM (4 of these for a 16k total) // - 02640-60086 Asynchronous data comm +// - 02640-60137 CTU interface +// - 02640-60032 Read/write PCA // // The following table summarizes the emulated character sets. The 2641A only // had room for a single optional character set (line drawing here) after the @@ -67,6 +69,8 @@ // - 02640-60192 Control storage (firmware ROMs & 256-byte SRAM) // - 02640-60065 4k DRAM (4 of these for a 16k total) // - 02640-60086 Asynchronous data comm +// - 02640-60137 CTU interface +// - 02640-60032 Read/write PCA // // The following table summarizes the emulated character sets. // @@ -97,7 +101,6 @@ // - LEDs are not output. // - RESET key is not implemented. // - A few TODOs here & there. -// - DC100 data cassettes are not emulated. #include "emu.h" #include "screen.h" @@ -106,6 +109,7 @@ #include "bus/rs232/rs232.h" #include "machine/ay31015.h" #include "machine/clock.h" +#include "machine/hp2640_tape.h" #include "sound/beep.h" #include "emupal.h" #include "speaker.h" @@ -215,6 +219,10 @@ protected: TIMER_DEVICE_CALLBACK_MEMBER(timer_beep_exp); + DECLARE_WRITE_LINE_MEMBER(tape_irq_w); + + uint8_t poll_r(); + void cpu_mem_map(address_map &map); void cpu_io_map(address_map &map); @@ -233,10 +241,13 @@ protected: required_device m_uart_clock; required_device m_beep; required_device m_timer_beep; + required_device m_tapes; + memory_view m_io_view; uint8_t m_mode_byte; bool m_timer_irq; bool m_datacom_irq; + bool m_tape_irq; // Character generators required_region_ptr_array m_chargen; @@ -297,6 +308,8 @@ hp2640_base_state::hp2640_base_state(const machine_config &mconfig, device_type m_uart_clock(*this , "uart_clock"), m_beep(*this , "beep"), m_timer_beep(*this , "timer_beep"), + m_tapes(*this , "tapes"), + m_io_view(*this , "io_view"), m_chargen(*this , "chargen%u" , 0), m_chargen_set{ m_cg_0 , m_cg_1 , m_cg_2 , m_cg_3} { @@ -310,6 +323,7 @@ void hp2640_base_state::machine_start() save_item(NAME(m_mode_byte)); save_item(NAME(m_timer_irq)); save_item(NAME(m_datacom_irq)); + save_item(NAME(m_tape_irq)); } void hp2640_base_state::machine_reset() @@ -317,6 +331,7 @@ void hp2640_base_state::machine_reset() m_mode_byte = 0; m_timer_irq = false; m_datacom_irq = false; + m_tape_irq = false; m_timer_10ms->reset(); update_irq(); m_blanking = true; @@ -339,7 +354,10 @@ IRQ_CALLBACK_MEMBER(hp2640_base_state::irq_callback) uint8_t res; // Encode interrupts in restart instruction (in order of decreasing priority) - if (m_datacom_irq && !BIT(m_mode_byte , 4)) { + if (m_tape_irq) { + // RST 5 + res = 0xef; + } else if (m_datacom_irq && !BIT(m_mode_byte , 4)) { // RST 4 res = 0xe7; } else if (m_timer_irq && !BIT(m_mode_byte , 5)) { @@ -366,6 +384,8 @@ void hp2640_base_state::mode_byte_w(uint8_t data) m_timer_irq = false; } update_irq(); + + m_io_view.select(BIT(m_mode_byte , 6)); } TIMER_DEVICE_CALLBACK_MEMBER(hp2640_base_state::timer_10ms_exp) @@ -549,9 +569,23 @@ TIMER_DEVICE_CALLBACK_MEMBER(hp2640_base_state::timer_beep_exp) m_beep->set_state(0); } +WRITE_LINE_MEMBER(hp2640_base_state::tape_irq_w) +{ + m_tape_irq = state; + update_irq(); +} + +uint8_t hp2640_base_state::poll_r() +{ + uint8_t res = m_tapes->poll_r(); + LOG("POLL %02x\n" , res); + return res; +} + void hp2640_base_state::update_irq() { - bool state = (m_datacom_irq && !BIT(m_mode_byte , 4)) || + bool state = m_tape_irq || + (m_datacom_irq && !BIT(m_mode_byte , 4)) || (m_timer_irq && !BIT(m_mode_byte , 5)); m_cpu->set_input_line(I8085_INTR_LINE , state); } @@ -1012,19 +1046,40 @@ void hp2640_base_state::cpu_mem_map(address_map &map) { map.unmap_value_low(); map(0x0000, 0x57ff).rom(); - map(0x8100, 0x8100).r(m_uart, FUNC(ay51013_device::receive)); - map(0x8120, 0x8120).r(FUNC(hp2640_base_state::async_status_r)); + map(0x8000, 0x8fff).view(m_io_view); + + // View 0 is for normal I/O + // View 1 is for poll read + // Writing is independent of poll state + m_io_view[ 0 ](0x0100, 0x0100).r(m_uart, FUNC(ay51013_device::receive)); + m_io_view[ 0 ](0x0120, 0x0120).r(FUNC(hp2640_base_state::async_status_r)); + map(0x8140, 0x8140).w(FUNC(hp2640_base_state::async_control_w)); map(0x8160, 0x8160).w(m_uart, FUNC(ay51013_device::transmit)); map(0x8300, 0x8300).w(FUNC(hp2640_base_state::kb_led_w)); - map(0x8300, 0x830d).r(FUNC(hp2640_base_state::kb_r)); - map(0x830e, 0x830e).r(FUNC(hp2640_base_state::switches_ah_r)); - map(0x830f, 0x830f).r(FUNC(hp2640_base_state::datacomm_sw_r)); + + m_io_view[ 0 ](0x0300, 0x030d).r(FUNC(hp2640_base_state::kb_r)); + m_io_view[ 0 ](0x030e, 0x030e).r(FUNC(hp2640_base_state::switches_ah_r)); + m_io_view[ 0 ](0x030f, 0x030f).r(FUNC(hp2640_base_state::datacomm_sw_r)); + map(0x8320, 0x8320).w(FUNC(hp2640_base_state::kb_prev_w)); - map(0x8380, 0x8380).rw(FUNC(hp2640_base_state::switches_jr_r), FUNC(hp2640_base_state::kb_reset_w)); - map(0x83a0, 0x83a0).r(FUNC(hp2640_base_state::switches_sz_r)); + map(0x8380, 0x8380).w(FUNC(hp2640_base_state::kb_reset_w)); + + m_io_view[ 0 ](0x0380, 0x0380).r(FUNC(hp2640_base_state::switches_jr_r)); + m_io_view[ 0 ](0x03a0, 0x03a0).r(FUNC(hp2640_base_state::switches_sz_r)); + map(0x8700, 0x8700).w(FUNC(hp2640_base_state::cx_w)); map(0x8720, 0x8720).w(FUNC(hp2640_base_state::cy_w)); + map(0x8b00, 0x8b00).w(m_tapes, FUNC(hp2640_tape_device::command_w)); + + m_io_view[ 0 ](0x0b00, 0x0b00).r(m_tapes, FUNC(hp2640_tape_device::status_r)); + + map(0x8b20, 0x8b20).w(m_tapes, FUNC(hp2640_tape_device::data_w)); + + m_io_view[ 0 ](0x0b20, 0x0b20).r(m_tapes, FUNC(hp2640_tape_device::data_r)); + + m_io_view[ 1 ](0x0000, 0x0fff).r(FUNC(hp2640_base_state::poll_r)); + map(0x9100, 0x91ff).ram(); map(0xc000, 0xffff).ram(); } @@ -1075,6 +1130,10 @@ void hp2640_base_state::hp2640_base(machine_config &config) SPEAKER(config, "mono").front_center(); BEEP(config, m_beep, BEEP_FREQUENCY).add_route(ALL_OUTPUTS, "mono", 1.00); TIMER(config, m_timer_beep).configure_generic(FUNC(hp2640_base_state::timer_beep_exp)); + + // Tape drives + HP2640_TAPE(config , m_tapes , SYS_CLOCK); + m_tapes->irq().set(FUNC(hp2640_base_state::tape_irq_w)); } // ************ diff --git a/src/mame/drivers/hp9845.cpp b/src/mame/drivers/hp9845.cpp index ce87c4ca60c..ed279a0d64c 100644 --- a/src/mame/drivers/hp9845.cpp +++ b/src/mame/drivers/hp9845.cpp @@ -451,6 +451,9 @@ void hp9845_base_state::machine_start() m_screen->register_screen_bitmap(m_bitmap); + m_t15->set_name("T15"); + m_t14->set_name("T14"); + // setup RAM dynamically for -ramsize // 0K..64K setup_ram_block(0 , 0); diff --git a/src/mame/machine/hp2640_tape.cpp b/src/mame/machine/hp2640_tape.cpp new file mode 100644 index 00000000000..ad22cc1c884 --- /dev/null +++ b/src/mame/machine/hp2640_tape.cpp @@ -0,0 +1,569 @@ +// license:BSD-3-Clause +// copyright-holders: F. Ulivi +/********************************************************************* + + hp2640_tape.cpp + + Tape subsystem of HP264x terminals + + Tape subsystem is composed of two DC100 drives and two cards: + 02640-60137 CTU interface + 02640-60032 Read/write PCA + + Data is recorded on a single track with Manchester modulation. + This modulation produces a maximum flux transition + density of 1600 transitions per inch. Bytes are recorded from + LSB to MSB. A "0" bit is recorded as 10, a "1" as 01. + HP264x tapes are not compatible with HP9825, HP85 & HP9845 systems + despite using the same DC100 cartridges. The latter systems record + data with a different modulation (delta-distance) and use two tracks. + + Format of records on tape: + 0..3 Preamble = 00 00 00 80 + 4..5 Length of record, MSB first + 6..x Record data + x+1 Checksum + x+2..x+5 Postamble = 01 00 00 00 (which is just the preamble in + reverse) + + Most significant bit of record length is set to 1 when starting + a file header. In this case there's just one byte of data carrying + the file number. + + Gaps of about 0.85" separate data records. A file header is + surrounded by two gaps of about 1.7" length. End of data on tape + is marked by 11" of gap. + + Reference docs: + + 13255-91032, Cartridge tape module + 13255-91137, Extended CTU interface module + +*********************************************************************/ + +#include "emu.h" +#include "hp2640_tape.h" + +// Debugging +#include "logmacro.h" +#undef VERBOSE +#define VERBOSE 0 +//#define VERBOSE (LOG_GENERAL) + +// Bit manipulation +namespace { + template constexpr T BIT_MASK(unsigned n) + { + return (T)1U << n; + } + + template void BIT_CLR(T& w , unsigned n) + { + w &= ~BIT_MASK(n); + } + + template void BIT_SET(T& w , unsigned n) + { + w |= BIT_MASK(n); + } +} + +// Timers +enum { + GAP_TMR_ID, + CELL_TMR_ID +}; + +// Constants +constexpr double FAST_SPEED = 60.0; // Fast speed: 60 ips +constexpr double SLOW_SPEED = 10.0; // Slow speed: 10 ips +constexpr double MOVING_THRESHOLD = 1.0; // Tape is moving when speed > 1.0 ips +constexpr double ACCELERATION = 2000.0; // Acceleration when speed set point is changed: 2000 ips^2 +// 58.4 tachometer pulses per inch +constexpr hti_format_t::tape_pos_t TACH_TICK_LENGTH = static_cast(hti_format_t::ONE_INCH_POS / 58.4); +constexpr uint8_t MODULUS_RESET = 0b10110011; // Reset value of modulus: -77 +constexpr unsigned GAP_TIME_MS = 1; // 1 ms to detect start/end of gaps + +// Bits in command register +enum : unsigned { + CMD_REG_LEFT_LIGHT_BIT = 7, // Light of left drive (1) + CMD_REG_RIGHT_LIGHT_BIT = 6,// Light of right drive (1) + CMD_REG_GAP_WRITE_BIT = 5, // Write gap (1) + CMD_REG_LEFT_SEL_BIT = 4, // Select left (1) or right (0) drive + CMD_REG_WRITE_BIT = 3, // Read (0) or Write (1) + CMD_REG_SPEED_BIT = 2, // Slow (0) or Fast (1) + CMD_REG_DIR_BIT = 1, // Reverse (0) or Forward (1) + CMD_REG_RUN_BIT = 0 // Stop (0) or Run (1) +}; + +// Bits in status register +enum : unsigned { + STAT_REG_TACH_INT_BIT = 7, // Tachometer tick interrupt (1) + STAT_REG_BYTE_READY_BIT = 6,// Byte ready (1) + STAT_REG_GAP_BIT = 5, // Gap detected (1) + STAT_REG_HOLE_INT_BIT = 4, // Hole interrupt (1) + STAT_REG_TACH_DIV2_BIT = 3, // Tach/2 + STAT_REG_RIP_BIT = 2, // Record in progress (1) + STAT_REG_RIGHT_CIN_BIT = 1, // Right cartridge in (1) + STAT_REG_LEFT_CIN_BIT = 0 // Left cartridge in (1) +}; + +// device type definition +DEFINE_DEVICE_TYPE(HP2640_TAPE, hp2640_tape_device, "hp2640_tape" , "HP2640 tape subsystem") + +hp2640_tape_device::hp2640_tape_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, HP2640_TAPE, tag, owner, clock) + , m_irq_handler(*this) + , m_led0_handler(*this) + , m_led1_handler(*this) + , m_drives(*this , "unit%u" , 0) +{ +} + +void hp2640_tape_device::command_w(uint8_t cmd) +{ + auto cmd_reg_diff = m_cmd_reg ^ cmd; + m_cmd_reg = cmd; + + LOG("CMD=%02x D=%02x\n" , m_cmd_reg , cmd_reg_diff); + + m_led0_handler(BIT(m_cmd_reg , CMD_REG_LEFT_LIGHT_BIT)); + m_led1_handler(BIT(m_cmd_reg , CMD_REG_RIGHT_LIGHT_BIT)); + + if (BIT(cmd_reg_diff , CMD_REG_LEFT_SEL_BIT)) { + // Drive selection changed, deselect old drive + m_drives[ m_selected_drive ]->set_op(hp_dc100_tape_device::OP_IDLE); + m_drives[ m_selected_drive ]->set_speed_setpoint(hp_dc100_tape_device::SP_STOP , false); + m_selected_drive = BIT(m_cmd_reg , CMD_REG_LEFT_SEL_BIT) ? 0 : 1; + } + + if (cmd_reg_diff & + (BIT_MASK(CMD_REG_RUN_BIT) | + BIT_MASK(CMD_REG_DIR_BIT) | + BIT_MASK(CMD_REG_SPEED_BIT) | + BIT_MASK(CMD_REG_WRITE_BIT) | + BIT_MASK(CMD_REG_LEFT_SEL_BIT) | + BIT_MASK(CMD_REG_GAP_WRITE_BIT))) { + // Drive selection and/or speed and/or r/w operation changed + + // ISF == true when running forward at slow speed + m_isf = (m_cmd_reg & (BIT_MASK(CMD_REG_RUN_BIT) | BIT_MASK(CMD_REG_DIR_BIT) | BIT_MASK(CMD_REG_SPEED_BIT))) == + (BIT_MASK(CMD_REG_RUN_BIT) | BIT_MASK(CMD_REG_DIR_BIT)); + + if (!BIT(m_cmd_reg , CMD_REG_WRITE_BIT)) { + m_current_op = hp_dc100_tape_device::OP_READ; + } else if (m_isf && BIT(m_cmd_reg , CMD_REG_WRITE_BIT) && !BIT(m_cmd_reg , CMD_REG_GAP_WRITE_BIT)) { + m_current_op = hp_dc100_tape_device::OP_WRITE; + } else if (BIT(m_cmd_reg , CMD_REG_WRITE_BIT) && BIT(m_cmd_reg , CMD_REG_GAP_WRITE_BIT)) { + m_current_op = hp_dc100_tape_device::OP_ERASE; + } else { + m_current_op = hp_dc100_tape_device::OP_IDLE; + } + + if (!set_speed()) { + start_rd_wr(); + } + } +} + +uint8_t hp2640_tape_device::status_r() +{ + uint8_t res = 0; + + if (m_tach_latch) { + BIT_SET(res , 7); + } + if (m_byte_ready) { + BIT_SET(res , 6); + } + if (m_gap) { + BIT_SET(res , 5); + } + if (m_hole_latch) { + BIT_SET(res , 4); + } + if (m_tach_div2) { + BIT_SET(res , 3); + } + if (m_rip) { + BIT_SET(res , 2); + } + if (!m_drives[ 1 ]->cart_out_r()) { + BIT_SET(res , 1); + } + if (!m_drives[ 0 ]->cart_out_r()) { + BIT_SET(res , 0); + } + + m_tach_latch = false; + m_hole_latch = false; + update_irq(); + + LOG("STS=%02x\n" , res); + return res; +} + +void hp2640_tape_device::data_w(uint8_t data) +{ + LOG("DATA W=%02x\n" , data); + m_data_rd = data; + m_byte_ready = false; + update_irq(); +} + +uint8_t hp2640_tape_device::data_r() +{ + m_byte_ready = false; + update_irq(); + + LOG("DATA R=%02x\n" , m_data_rd); + return m_data_rd; +} + +uint8_t hp2640_tape_device::poll_r() const +{ + return m_irq ? 0x80 : 0x00; +} + +void hp2640_tape_device::device_add_mconfig(machine_config &config) +{ + for (unsigned i = 0; i < 2; i++) { + auto& finder = m_drives[ i ]; + + HP_DC100_TAPE(config , finder , 0); + // Acceleration: 2000 in/s^2 + finder->set_acceleration(ACCELERATION); + // Slow speed: 10 ips, Fast speed: 60 ips + finder->set_set_points(SLOW_SPEED , FAST_SPEED); + // 58.4 ticks per inch + finder->set_tick_size(TACH_TICK_LENGTH); + // Manchester encoded data + finder->set_image_format(hti_format_t::HTI_MANCHESTER_MOD); + // Moving when speed is >1 ips + finder->set_go_threshold(MOVING_THRESHOLD); + // Unit name: U0/U1 + finder->set_name(string_format("U%u" , i)); + + finder->hole().set([this , i](int state) { hole_w(i , state); }); + finder->tacho_tick().set([this , i](int state) { tacho_tick_w(i , state); }); + finder->motion_event().set([this , i](int state) { motion_w(i , state); }); + finder->rd_bit().set([this , i](int state) { rd_bit_w(i , state); }); + finder->wr_bit().set([this , i](int state) { return wr_bit_r(i); }); + } +} + +void hp2640_tape_device::device_start() +{ + m_irq_handler.resolve_safe(); + m_led0_handler.resolve_safe(); + m_led1_handler.resolve_safe(); + + m_gap_timer = timer_alloc(GAP_TMR_ID); + m_cell_timer = timer_alloc(CELL_TMR_ID); + + save_item(NAME(m_selected_drive)); + save_item(NAME(m_cmd_reg)); + save_item(NAME(m_data_rd)); + save_item(NAME(m_data_sr)); + save_item(NAME(m_modulus)); + save_item(NAME(m_cell_cnt)); + save_item(NAME(m_bit_cnt)); + save_item(NAME(m_tach_div2)); + save_item(NAME(m_tach_latch)); + save_item(NAME(m_hole_latch)); + save_item(NAME(m_byte_ready)); + save_item(NAME(m_irq)); + save_item(NAME(m_bit_sync)); + save_item(NAME(m_wr_bit)); + save_item(NAME(m_last_rd_bit)); + save_item(NAME(m_isf)); + save_item(NAME(m_gap)); + save_item(NAME(m_prev_gap)); + save_item(NAME(m_rip)); +} + +void hp2640_tape_device::device_reset() +{ + m_selected_drive = 0; + + // All bits set to 1 but 3 & 0 + m_cmd_reg = ~0; + BIT_CLR(m_cmd_reg , CMD_REG_WRITE_BIT); + BIT_CLR(m_cmd_reg , CMD_REG_RUN_BIT); + + m_modulus = MODULUS_RESET; + m_cell_cnt = 6; + m_bit_cnt = 8; + m_tach_div2 = false; + m_tach_latch = false; + m_hole_latch = false; + m_byte_ready = false; + m_irq = true; + m_bit_sync = false; + m_isf = false; + m_gap = true; + m_prev_gap = true; + m_rip = false; + m_current_op = hp_dc100_tape_device::OP_READ; + update_irq(); + + m_gap_timer->reset(); + m_cell_timer->reset(); +} + +void hp2640_tape_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + LOG("TMR %d @%s\n" , id , machine().time().to_string()); + + switch (id) { + case GAP_TMR_ID: + m_gap = !m_gap; + if (m_gap) { + set_gap(); + } else { + LOG("GAP ENDS\n"); + load_gap_timer(); + if (m_isf) { + load_modulus(); + } + } + break; + + case CELL_TMR_ID: + if (m_current_op == hp_dc100_tape_device::OP_READ) { + m_cell_cnt++; + if (m_cell_cnt == 15) { + restart_cell_cnt(); + } else { + load_modulus(); + } + } + break; + + default: + break; + } +} + +void hp2640_tape_device::hole_w(unsigned drive , int state) +{ + if (state && drive == m_selected_drive) { + LOG("HOLE\n"); + m_hole_latch = true; + BIT_CLR(m_cmd_reg, CMD_REG_RUN_BIT); + set_speed(); + update_irq(); + } +} + +void hp2640_tape_device::tacho_tick_w(unsigned drive , int state) +{ + if (state && drive == m_selected_drive) { + m_tach_div2 = !m_tach_div2; + if (m_tach_div2) { + LOG("HALF TICK\n"); + m_tach_latch = true; + update_irq(); + } + } +} + +void hp2640_tape_device::motion_w(unsigned drive , int state) +{ + if (state && drive == m_selected_drive) { + LOG("MOTION\n"); + start_rd_wr(); + } +} + +void hp2640_tape_device::rd_bit_w(unsigned drive , int state) +{ + if (drive == m_selected_drive) { + bool rd_bit = state != 0; + bool transition = rd_bit != m_last_rd_bit; + m_last_rd_bit = rd_bit; + + LOG("RD BIT %d TR %d GP %d IS %d CC %u MD %u @%s\n" , rd_bit , transition , m_gap , m_isf , m_cell_cnt , m_modulus , machine().time().to_string()); + + if (transition) { + if (m_gap) { + if (m_prev_gap) { + m_prev_gap = false; + load_gap_timer(); + } + } else { + load_gap_timer(); + + if (m_isf) { + if (BIT(m_cell_cnt , 3)) { + // Adjust modulus by +/- 1 + if (BIT(m_cell_cnt , 1)) { + m_modulus--; + } else { + m_modulus++; + } + } + bool prev_bit_sync = m_bit_sync; + if ((m_cell_cnt & 0xc) == 0xc) { + if (m_bit_sync) { + // Shift in read bit + LOG("BIT %d CNT %u\n" , rd_bit , m_bit_cnt); + m_data_sr >>= 1; + if (rd_bit) { + BIT_SET(m_data_sr, 7); + } + m_bit_cnt++; + if (m_bit_cnt == 16) { + LOG("RD DATA=%02x\n" , m_data_sr); + m_bit_cnt = 8; + m_data_rd = m_data_sr; + m_byte_ready = true; + update_irq(); + } + } else if (rd_bit) { + // Sync achieved + LOG("SYNC\n"); + m_bit_sync = true; + m_bit_cnt = 8; + m_byte_ready = true; + update_irq(); + } + } + if (BIT(m_cell_cnt , 2) || !prev_bit_sync) { + restart_cell_cnt(); + } + } + } + } + } +} + +int hp2640_tape_device::wr_bit_r(unsigned drive) +{ + if (drive == m_selected_drive) { + // IRL the m_cell_cnt counts in [6..13] range + if (m_cell_cnt == 6) { + m_cell_cnt = 13; + m_wr_bit = !BIT(m_data_sr , 0); + } else if (m_cell_cnt == 13) { + m_cell_cnt = 6; + m_wr_bit = !m_wr_bit; + m_bit_cnt++; + if (m_bit_cnt == 16) { + m_data_sr = m_data_rd; + m_bit_cnt = 8; + m_byte_ready = true; + update_irq(); + } else { + m_data_sr >>= 1; + } + } + return m_wr_bit; + } else { + return 0; + } +} + +void hp2640_tape_device::update_irq() +{ + bool new_irq = m_tach_latch || m_hole_latch || m_byte_ready; + + if (new_irq != m_irq) { + LOG("IRQ %d\n" , new_irq); + m_irq = new_irq; + m_irq_handler(m_irq); + } +} + +bool hp2640_tape_device::set_speed() +{ + hp_dc100_tape_device::tape_speed_t sp; + + if (!BIT(m_cmd_reg , CMD_REG_RUN_BIT)) { + sp = hp_dc100_tape_device::SP_STOP; + } else if (BIT(m_cmd_reg , CMD_REG_SPEED_BIT)) { + sp = hp_dc100_tape_device::SP_FAST; + } else { + sp = hp_dc100_tape_device::SP_SLOW; + } + + bool changed = m_drives[ m_selected_drive ]->set_speed_setpoint(sp , BIT(m_cmd_reg , CMD_REG_DIR_BIT)); + + if (changed) { + start_rd_wr(true); + } + + return changed; +} + +void hp2640_tape_device::start_rd_wr(bool recalc) +{ + hp_dc100_tape_device& drive = *m_drives[ m_selected_drive ]; + + m_rip = false; + + if (drive.is_above_threshold() && m_current_op == hp_dc100_tape_device::OP_READ) { + // Reading + LOG("START RD GP %d IS %d\n" , m_gap , m_isf); + drive.set_op(hp_dc100_tape_device::OP_READ , recalc); + if (m_gap) { + m_modulus = MODULUS_RESET; + m_bit_sync = false; + stop_cell_cnt(); + } + if (!m_isf) { + stop_cell_cnt(); + } + } else if (!drive.is_accelerating() && !drive.wpr_r() && m_current_op == hp_dc100_tape_device::OP_WRITE) { + // Data writing + LOG("START WR\n"); + stop_cell_cnt(); + drive.set_op(hp_dc100_tape_device::OP_WRITE); + } else if (!drive.wpr_r() && m_current_op == hp_dc100_tape_device::OP_ERASE) { + // Gap writing + LOG("START ERASE\n"); + m_rip = true; + m_data_sr = 0; + m_bit_cnt = 8; + stop_cell_cnt(); + drive.set_op(hp_dc100_tape_device::OP_ERASE); + } else { + LOG("IDLE\n"); + stop_cell_cnt(); + drive.set_op(hp_dc100_tape_device::OP_IDLE); + } +} + +void hp2640_tape_device::load_modulus() +{ + m_cell_timer->adjust(clocks_to_attotime(256U - m_modulus)); +} + +void hp2640_tape_device::restart_cell_cnt() +{ + m_cell_cnt = 6; + load_modulus(); +} + +void hp2640_tape_device::stop_cell_cnt() +{ + m_cell_cnt = 6; + m_cell_timer->reset(); +} + +void hp2640_tape_device::set_gap() +{ + LOG("GAP START\n"); + m_gap = true; + m_prev_gap = true; + if (m_drives[ m_selected_drive ]->get_op() == hp_dc100_tape_device::OP_READ) { + m_modulus = MODULUS_RESET; + m_bit_sync = false; + stop_cell_cnt(); + } +} + +void hp2640_tape_device::load_gap_timer() +{ + m_gap_timer->adjust(attotime::from_msec(GAP_TIME_MS)); +} diff --git a/src/mame/machine/hp2640_tape.h b/src/mame/machine/hp2640_tape.h new file mode 100644 index 00000000000..38733094dd5 --- /dev/null +++ b/src/mame/machine/hp2640_tape.h @@ -0,0 +1,96 @@ +// license:BSD-3-Clause +// copyright-holders: F. Ulivi +/********************************************************************* + + hp2640_tape.h + + Tape subsystem of HP264x terminals + +*********************************************************************/ + +#ifndef MAME_MACHINE_HP2640_TAPE_H +#define MAME_MACHINE_HP2640_TAPE_H + +#pragma once + +#include "machine/hp_dc100_tape.h" + +class hp2640_tape_device : public device_t +{ +public: + // construction/destruction + hp2640_tape_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + // callbacks + auto irq() { return m_irq_handler.bind(); } + auto led_0() { return m_led0_handler.bind(); } + auto led_1() { return m_led1_handler.bind(); } + + // I/O + void command_w(uint8_t cmd); + uint8_t status_r (); + void data_w (uint8_t data); + uint8_t data_r (); + uint8_t poll_r () const; + +protected: + // device-level overrides + virtual void device_add_mconfig(machine_config &config) override; + virtual void device_start() override; + virtual void device_reset() override; + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; + +private: + devcb_write_line m_irq_handler; + devcb_write_line m_led0_handler; + devcb_write_line m_led1_handler; + + // 0 is left hand drive + // 1 is right hand drive + required_device_array m_drives; + + // State + uint8_t m_selected_drive; // U35-10 + uint8_t m_cmd_reg; // U35 & others + uint8_t m_data_rd; // U32 & U33 + uint8_t m_data_sr; // U42 & U43 + uint8_t m_modulus; // U49 & U59 + uint8_t m_cell_cnt; // U210 + uint8_t m_bit_cnt; // U310 + bool m_tach_div2; // U19-6 + bool m_tach_latch; // U21-10 + bool m_hole_latch; // U21-6 + bool m_byte_ready; // U19-9 + bool m_irq; // U48-8 + bool m_bit_sync; // U110-6 + bool m_wr_bit; // U110-10 + bool m_last_rd_bit; + bool m_isf; // U36-6 + bool m_gap; + bool m_prev_gap; + bool m_rip; + hp_dc100_tape_device::tape_op_t m_current_op; + + // Timers + emu_timer *m_gap_timer; + emu_timer *m_cell_timer; + + void hole_w(unsigned drive , int state); + void tacho_tick_w(unsigned drive , int state); + void motion_w(unsigned drive , int state); + void rd_bit_w(unsigned drive , int state); + int wr_bit_r(unsigned drive); + void update_irq(); + bool set_speed(); + void start_rd_wr(bool recalc = false); + void load_modulus(); + void restart_cell_cnt(); + void stop_cell_cnt(); + void set_gap(); + void load_gap_timer(); +}; + +// device type definition +DECLARE_DEVICE_TYPE(HP2640_TAPE, hp2640_tape_device) + +#endif /* MAME_MACHINE_HP2640_TAPE_H */ diff --git a/src/mame/machine/hp9825_tape.cpp b/src/mame/machine/hp9825_tape.cpp index c3eac66adff..dd85bdfbe09 100644 --- a/src/mame/machine/hp9825_tape.cpp +++ b/src/mame/machine/hp9825_tape.cpp @@ -92,7 +92,7 @@ void hp9825_tape_device::device_add_mconfig(machine_config &config) m_tape->set_acceleration(ACCELERATION); m_tape->set_set_points(SLOW_SPEED , FAST_SPEED); m_tape->set_tick_size(TACH_TICK_LENGTH); - m_tape->set_bits_per_word(17); + m_tape->set_image_format(hti_format_t::HTI_DELTA_MOD_17_BITS); m_tape->set_go_threshold(MOVING_THRESHOLD); m_tape->cart_out().set(FUNC(hp9825_tape_device::cart_out_w)); m_tape->hole().set(FUNC(hp9825_tape_device::hole_w)); diff --git a/src/tools/imgtool/modules/hp85_tape.cpp b/src/tools/imgtool/modules/hp85_tape.cpp index fbdef06a7cb..0198b6251dd 100644 --- a/src/tools/imgtool/modules/hp85_tape.cpp +++ b/src/tools/imgtool/modules/hp85_tape.cpp @@ -145,7 +145,7 @@ typedef struct { tape_image_85::tape_image_85(void) : dirty(false) { - image.set_bits_per_word(16); + image.set_image_format(hti_format_t::HTI_DELTA_MOD_16_BITS); } void tape_image_85::format_img(void) diff --git a/src/tools/imgtool/modules/hp9845_tape.cpp b/src/tools/imgtool/modules/hp9845_tape.cpp index e9abc99789c..7a3e90b08d1 100644 --- a/src/tools/imgtool/modules/hp9845_tape.cpp +++ b/src/tools/imgtool/modules/hp9845_tape.cpp @@ -324,7 +324,7 @@ static const struct io_procs my_stream_procs = { imgtoolerr_t tape_image_t::load_from_file(imgtool::stream *stream) { hti_format_t inp_image; - inp_image.set_bits_per_word(16); + inp_image.set_image_format(hti_format_t::HTI_DELTA_MOD_16_BITS); io_generic io; io.file = (void *)stream;