Merge pull request #628 from fulivi/hp9845_dev

Hp9845: tape driver added [F. Ulivi]
This commit is contained in:
Miodrag Milanović 2016-02-17 11:41:45 +01:00
commit 4d8d9095a1
6 changed files with 1713 additions and 20 deletions

View File

@ -771,6 +771,18 @@ if (MACHINES["HD64610"]~=null) then
}
end
---------------------------------------------------
--
--@src/devices/machine/hp_taco.h,MACHINES["HP_TACO"] = true
---------------------------------------------------
if (MACHINES["HP_TACO"]~=null) then
files {
MAME_DIR .. "src/devices/machine/hp_taco.cpp",
MAME_DIR .. "src/devices/machine/hp_taco.h",
}
end
---------------------------------------------------
--
--@src/devices/machine/i2cmem.h,MACHINES["I2CMEM"] = true

View File

@ -398,6 +398,7 @@ MACHINES["ER2055"] = true
MACHINES["F3853"] = true
MACHINES["HD63450"] = true
MACHINES["HD64610"] = true
MACHINES["HP_TACO"] = true
MACHINES["I2CMEM"] = true
MACHINES["I80130"] = true
MACHINES["I8089"] = true

View File

@ -673,12 +673,7 @@ UINT16 hp_hybrid_cpu_device::RM(UINT32 addr)
return RIO(CURRENT_PA , addr_wo_bsc - HP_REG_R4_ADDR);
case HP_REG_IV_ADDR:
// Correct?
if (!BIT(m_flags , HPHYBRID_IRH_SVC_BIT) && !BIT(m_flags , HPHYBRID_IRL_SVC_BIT)) {
return m_reg_IV;
} else {
return m_reg_IV | CURRENT_PA;
}
return m_reg_IV;
case HP_REG_PA_ADDR:
return CURRENT_PA;
@ -1021,7 +1016,7 @@ void hp_hybrid_cpu_device::check_for_interrupts(void)
// Do a double-indirect JSM IV,I instruction
WM(AEC_CASE_C , ++m_reg_R , m_reg_P);
m_reg_P = RM(AEC_CASE_I , RM(HP_REG_IV_ADDR));
m_reg_P = RM(AEC_CASE_I , m_reg_IV + CURRENT_PA);
m_reg_I = fetch();
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,169 @@
// license:BSD-3-Clause
// copyright-holders:F. Ulivi
/*********************************************************************
hp_taco.h
HP TApe COntroller (5006-3012)
*********************************************************************/
#ifndef __HP_TACO_H__
#define __HP_TACO_H__
#include <map>
#define MCFG_TACO_IRQ_HANDLER(_devcb) \
devcb = &hp_taco_device::set_irq_handler(*device , DEVCB_##_devcb);
#define MCFG_TACO_FLG_HANDLER(_devcb) \
devcb = &hp_taco_device::set_flg_handler(*device , DEVCB_##_devcb);
#define MCFG_TACO_STS_HANDLER(_devcb) \
devcb = &hp_taco_device::set_sts_handler(*device , DEVCB_##_devcb);
class hp_taco_device : public device_t ,
public device_image_interface
{
public:
// construction/destruction
hp_taco_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname);
hp_taco_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
// static configuration helpers
template<class _Object> static devcb_base &set_irq_handler(device_t &device, _Object object) { return downcast<hp_taco_device &>(device).m_irq_handler.set_callback(object); }
template<class _Object> static devcb_base &set_flg_handler(device_t &device, _Object object) { return downcast<hp_taco_device &>(device).m_flg_handler.set_callback(object); }
template<class _Object> static devcb_base &set_sts_handler(device_t &device, _Object object) { return downcast<hp_taco_device &>(device).m_sts_handler.set_callback(object); }
// Register read/write
DECLARE_WRITE16_MEMBER(reg_w);
DECLARE_READ16_MEMBER(reg_r);
// Flag & status read
DECLARE_READ_LINE_MEMBER(flg_r);
DECLARE_READ_LINE_MEMBER(sts_r);
// device_image_interface overrides
virtual bool call_load() override;
virtual bool call_create(int format_type, option_resolution *format_options) override;
virtual void call_unload() override;
virtual iodevice_t image_type() const override { return IO_MAGTAPE; }
virtual bool is_readable() const override { return true; }
virtual bool is_writeable() const override { return true; }
virtual bool is_creatable() const override { return true; }
virtual bool must_be_loaded() const override { return false; }
virtual bool is_reset_on_load() const override { return false; }
virtual const char *file_extensions() const override;
virtual const option_guide *create_option_guide() const override { return nullptr; }
// Tape position, 1 unit = 1 inch / (968 * 1024)
typedef INT32 tape_pos_t;
// Words stored on tape
typedef UINT16 tape_word_t;
protected:
// device-level overrides
virtual void device_config_complete() override;
virtual void device_start() override;
virtual void device_stop() override;
virtual void device_reset() override;
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
private:
// Storage of tracks: mapping from a tape position to word stored there
typedef std::map<tape_pos_t , tape_word_t> tape_track_t;
devcb_write_line m_irq_handler;
devcb_write_line m_flg_handler;
devcb_write_line m_sts_handler;
// Registers
UINT16 m_data_reg;
bool m_data_reg_full;
UINT16 m_cmd_reg;
UINT16 m_status_reg;
UINT16 m_tach_reg;
UINT16 m_checksum_reg;
UINT16 m_timing_reg;
// State
bool m_irq;
bool m_flg;
bool m_sts;
UINT8 m_cmd_state;
// Tape position & motion
tape_pos_t m_tape_pos;
attotime m_start_time; // Tape moving if != never
bool m_tape_fwd;
bool m_tape_fast;
// Timers
emu_timer *m_tape_timer;
emu_timer *m_hole_timer;
// Content of tape tracks
tape_track_t m_tracks[ 2 ];
bool m_image_dirty;
// Reading & writing
bool m_tape_wr;
tape_pos_t m_rw_pos;
UINT16 m_next_word;
tape_track_t::iterator m_rd_it;
bool m_rd_it_valid;
// Gap detection
tape_pos_t m_gap_detect_start;
typedef enum {
ADV_NO_MORE_DATA,
ADV_CONT_DATA,
ADV_DISCONT_DATA
} adv_res_t;
void clear_state(void);
void irq_w(bool state);
void set_error(bool state);
unsigned speed_to_tick_freq(void) const;
bool pos_offset(tape_pos_t& pos , tape_pos_t offset) const;
void move_tape_pos(tape_pos_t delta_pos);
void update_tape_pos(void);
static void ensure_a_lt_b(tape_pos_t& a , tape_pos_t& b);
static bool any_hole(tape_pos_t tape_pos_a , tape_pos_t tape_pos_b);
tape_pos_t next_hole(void) const;
attotime time_to_distance(tape_pos_t distance) const;
attotime time_to_target(tape_pos_t target) const;
bool start_tape_cmd(UINT16 cmd_reg , UINT16 must_be_1 , UINT16 must_be_0);
void start_tape(UINT16 cmd_reg);
void stop_tape(void);
tape_track_t& current_track(void);
static tape_pos_t word_length(tape_word_t w);
static tape_pos_t word_end_pos(const tape_track_t::iterator& it);
static void adjust_it(tape_track_t& track , tape_track_t::iterator& it , tape_pos_t pos);
void write_word(tape_pos_t start , tape_word_t word , tape_pos_t& length);
void write_gap(tape_pos_t a , tape_pos_t b);
bool just_gap(tape_pos_t a , tape_pos_t b);
tape_pos_t farthest_end(const tape_track_t::iterator& it) const;
bool next_data(tape_track_t::iterator& it , tape_pos_t pos , bool inclusive);
adv_res_t adv_it(tape_track_t::iterator& it);
attotime fetch_next_wr_word(void);
attotime time_to_rd_next_word(tape_pos_t& word_rd_pos);
bool next_n_gap(tape_pos_t& pos , tape_track_t::iterator it , unsigned n_gaps , tape_pos_t min_gap);
bool next_n_gap(tape_pos_t& pos , unsigned n_gaps , tape_pos_t min_gap);
void clear_tape(void);
void dump_sequence(tape_track_t::const_iterator it_start , unsigned n_words);
void save_tape(void);
bool load_track(tape_track_t& track);
bool load_tape(void);
void set_tape_present(bool present);
attotime time_to_next_hole(void) const;
attotime time_to_tach_pulses(void) const;
void start_cmd_exec(UINT16 new_cmd_reg);
};
// device type definition
extern const device_type HP_TACO;
#endif /* __HP_TACO_H__ */

View File

@ -16,12 +16,12 @@
// - LPU & PPU ROMs
// - LPU & PPU RAMs
// - Text mode screen
// - Keyboard (most of keys)
// - Keyboard
// - T15 tape drive
// What's not yet in:
// - Beeper
// - Rest of keyboard
// - Graphic screen
// - Tape drive (this needs some heavy RE of the TACO chip)
// - Better naming of tape drive image (it's now "magt", should be "t15")
// - Better documentation of this file
// - Software list to load optional ROMs
// What's wrong:
@ -33,6 +33,7 @@
#include "cpu/z80/z80.h"
#include "softlist.h"
#include "cpu/hphybrid/hphybrid.h"
#include "machine/hp_taco.h"
#define BIT_MASK(n) (1U << (n))
@ -77,7 +78,8 @@ public:
m_io_key0(*this , "KEY0"),
m_io_key1(*this , "KEY1"),
m_io_key2(*this , "KEY2"),
m_io_key3(*this , "KEY3")
m_io_key3(*this , "KEY3"),
m_t15(*this , "t15")
{ }
UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
@ -90,7 +92,7 @@ public:
void vblank_w(screen_device &screen, bool state);
IRQ_CALLBACK_MEMBER(irq_callback);
void update_irl(void);
void update_irq(void);
TIMER_DEVICE_CALLBACK_MEMBER(kb_scan);
DECLARE_READ16_MEMBER(kb_scancode_r);
@ -99,6 +101,10 @@ public:
DECLARE_WRITE8_MEMBER(pa_w);
DECLARE_WRITE_LINE_MEMBER(t15_irq_w);
DECLARE_WRITE_LINE_MEMBER(t15_flg_w);
DECLARE_WRITE_LINE_MEMBER(t15_sts_w);
private:
required_device<hp_5061_3001_cpu_device> m_lpu;
required_device<hp_5061_3001_cpu_device> m_ppu;
@ -107,6 +113,7 @@ private:
required_ioport m_io_key1;
required_ioport m_io_key2;
required_ioport m_io_key3;
required_device<hp_taco_device> m_t15;
void set_video_mar(UINT16 mar);
void video_fill_buff(bool buff_idx);
@ -136,12 +143,15 @@ private:
// Interrupt handling
UINT8 m_irl_pending;
UINT8 m_irh_pending;
// State of keyboard
ioport_value m_kb_state[ 4 ];
UINT8 m_kb_scancode;
UINT16 m_kb_status;
// State of PPU I/O
UINT8 m_ppu_pa;
};
static INPUT_PORTS_START(hp9845b)
@ -322,10 +332,13 @@ void hp9845b_state::machine_reset()
m_video_frame = 0;
m_irl_pending = 0;
m_irh_pending = 0;
memset(&m_kb_state[ 0 ] , 0 , sizeof(m_kb_state));
m_kb_scancode = 0x7f;
m_kb_status = 0;
m_ppu_pa = 0;
}
void hp9845b_state::set_video_mar(UINT16 mar)
@ -479,13 +492,14 @@ IRQ_CALLBACK_MEMBER(hp9845b_state::irq_callback)
if (irqline == HPHYBRID_IRL) {
return m_irl_pending;
} else {
return 0;
return m_irh_pending;
}
}
void hp9845b_state::update_irl(void)
void hp9845b_state::update_irq(void)
{
m_ppu->set_input_line(HPHYBRID_IRL , m_irl_pending != 0);
m_ppu->set_input_line(HPHYBRID_IRH , m_irh_pending != 0);
}
TIMER_DEVICE_CALLBACK_MEMBER(hp9845b_state::kb_scan)
@ -546,7 +560,7 @@ TIMER_DEVICE_CALLBACK_MEMBER(hp9845b_state::kb_scan)
m_kb_scancode = i;
BIT_SET(m_irl_pending , 0);
BIT_SET(m_kb_status, 0);
update_irl();
update_irq();
// Special case: pressing stop key sets LPU "status" flag
if (i == 0x47) {
@ -572,24 +586,50 @@ WRITE16_MEMBER(hp9845b_state::kb_irq_clear_w)
{
BIT_CLR(m_irl_pending , 0);
BIT_CLR(m_kb_status, 0);
update_irl();
update_irq();
m_lpu->status_w(0);
// TODO: beeper start
}
WRITE8_MEMBER(hp9845b_state::pa_w)
{
m_ppu_pa = data;
// TODO: handle sts & flg
if (data == 0xf) {
// RHS tape drive (T15)
m_ppu->status_w(1);
m_ppu->flag_w(1);
if (data == 15) {
// RHS tape drive (T15)
m_ppu->status_w(m_t15->sts_r());
m_ppu->flag_w(m_t15->flg_r());
} else {
m_ppu->status_w(0);
m_ppu->flag_w(0);
}
}
WRITE_LINE_MEMBER(hp9845b_state::t15_irq_w)
{
if (state) {
BIT_SET(m_irh_pending , 7);
} else {
BIT_CLR(m_irh_pending , 7);
}
update_irq();
}
WRITE_LINE_MEMBER(hp9845b_state::t15_flg_w)
{
if (m_ppu_pa == 15) {
m_ppu->flag_w(state);
}
}
WRITE_LINE_MEMBER(hp9845b_state::t15_sts_w)
{
if (m_ppu_pa == 15) {
m_ppu->status_w(state);
}
}
static MACHINE_CONFIG_START( hp9845a, hp9845_state )
//MCFG_CPU_ADD("lpu", HP_5061_3010, XTAL_11_4MHz)
//MCFG_CPU_ADD("ppu", HP_5061_3011, XTAL_11_4MHz)
@ -638,6 +678,9 @@ static ADDRESS_MAP_START(ppu_io_map , AS_IO , 16 , hp9845b_state)
// PA = 0, IC = 3
// Keyboard status input & keyboard interrupt clear
AM_RANGE(HP_MAKE_IOADDR(0 , 3) , HP_MAKE_IOADDR(0 , 3)) AM_READWRITE(kb_status_r , kb_irq_clear_w)
// PA = 15, IC = 0..3
// Right-hand side tape drive (T15)
AM_RANGE(HP_MAKE_IOADDR(15 , 0) , HP_MAKE_IOADDR(15 , 3)) AM_DEVREADWRITE("t15" , hp_taco_device , reg_r , reg_w)
ADDRESS_MAP_END
static MACHINE_CONFIG_START( hp9845b, hp9845b_state )
@ -663,6 +706,12 @@ static MACHINE_CONFIG_START( hp9845b, hp9845b_state )
// Actual keyboard refresh rate should be KEY_SCAN_OSCILLATOR / 128 (2560 Hz)
MCFG_TIMER_DRIVER_ADD_PERIODIC("kb_timer" , hp9845b_state , kb_scan , attotime::from_hz(100))
// Tape controller
MCFG_DEVICE_ADD("t15" , HP_TACO , 4000000)
MCFG_TACO_IRQ_HANDLER(WRITELINE(hp9845b_state , t15_irq_w))
MCFG_TACO_FLG_HANDLER(WRITELINE(hp9845b_state , t15_flg_w))
MCFG_TACO_STS_HANDLER(WRITELINE(hp9845b_state , t15_sts_w))
MCFG_SOFTWARE_LIST_ADD("optrom_list", "hp9845b_rom")
MACHINE_CONFIG_END