hp9845: initial version of HP TACO driver (only basic tape movement is working)

This commit is contained in:
fulivi 2016-01-11 13:26:13 +01:00
parent 11f82be540
commit 408c6351cf
5 changed files with 681 additions and 10 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

@ -0,0 +1,516 @@
// license:BSD-3-Clause
// copyright-holders:F. Ulivi
/*********************************************************************
hp_taco.cpp
HP TApe COntroller (5006-3012)
*********************************************************************/
// Documentation I used:
// [1] HP, manual 64940-90905, may 80 rev. - Model 64940A tape control & drive service manual
// [2] US patent 4,075,679 describing HP9825 system (this system had a discrete implementation of tape controller)
// Format of TACO command/status register (R5)
// Bit R/W Content
// ===============
// 15 RW Tape direction (1 = forward)
// 14..10 RW Command
// 9 RW ? Drive ON according to [1], doesn't match usage of firmware
// 8 RW ? Size of gaps according to [1]
// 7 RW Speed of tape (1 = 90 ips, 0 = 22 ips)
// 6 RW Option bit for various commands
// 5 R Current track (1 = B)
// 4 R Gap detected (1)
// 3 R Write protection (1)
// 2 R Servo failure (1)
// 1 R Cartridge out (1)
// 0 R Hole detected (1)
// TODO: R6 è modificato durante il conteggio impulsi? Viene azzerato alla lettura?
#include "emu.h"
#include "hp_taco.h"
// Debugging
#define VERBOSE 1
#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
// Macros to clear/set single bits
#define BIT_MASK(n) (1U << (n))
#define BIT_CLR(w , n) ((w) &= ~BIT_MASK(n))
#define BIT_SET(w , n) ((w) |= BIT_MASK(n))
// Timers
enum {
TAPE_TMR_ID
};
// Constants
#define CMD_REG_MASK 0xffc0 // Command register mask
#define STATUS_REG_MASK 0x003f // Status register mask
#define STATUS_ERR_MASK 0x0002 // Mask of errors in status reg.
#define TACH_TICKS_PER_INCH 968 // Tachometer pulses per inch of tape movement
#define TACH_FREQ_SLOW 21276 // Tachometer pulse frequency for slow speed (21.98 ips)
#define TACH_FREQ_FAST 87196 // Tachometer pulse frequency for fast speed (90.08 ips)
#define TAPE_LENGTH ((140 * 12 + 72 * 2) * TACH_TICKS_PER_INCH) // Tape length (in tachometer pulses): 140 ft of usable tape + 72" of punched tape at either end
#define TAPE_INIT_POS (80 * TACH_TICKS_PER_INCH) // Initial tape position: 80" from beginning (just past the punched part)
#define QUICK_CMD_USEC 10 // usec for "quick" command execution
// Parts of command register
#define CMD_CODE(reg) \
(((reg) >> 10) & 0x1f)
#define DIR_FWD(reg) \
(BIT(reg , 15))
#define SPEED_FAST(reg) \
(BIT(reg , 7))
#define CMD_OPT(reg) \
(BIT(reg , 6))
// Commands
enum {
CMD_ALIGN_0, // 00: header alignment (?)
CMD_UNK_01, // 01: unknown
CMD_FINAL_GAP, // 02: write final gap
CMD_INIT_WRITE, // 03: write words for tape formatting
CMD_STOP, // 04: stop
CMD_UNK_05, // 05: unknown
CMD_SET_TRACK, // 06: set A/B track
CMD_UNK_07, // 07: unknown
CMD_UNK_08, // 08: unknown
CMD_UNK_09, // 09: unknown
CMD_MOVE, // 0a: move tape
CMD_UNK_0b, // 0b: unknown
CMD_UNK_0c, // 0c: unknown*
CMD_UNK_0d, // 0d: unknown
CMD_CLEAR, // 0e: clear errors/unlatch status bits
CMD_UNK_0f, // 0f: unknown
CMD_ALIGN_PREAMBLE, // 10: align to end of preamble (?)
CMD_UNK_11, // 11: unknown
CMD_UNK_12, // 12: unknown
CMD_UNK_13, // 13: unknown
CMD_UNK_14, // 14: unknown
CMD_UNK_15, // 15: unknown
CMD_WRITE_IRG, // 16: write inter-record gap
CMD_UNK_17, // 17: unknown
CMD_SCAN_RECORDS, // 18: scan records (count IRGs)
CMD_RECORD_WRITE, // 19: write record words
CMD_UNK_MOVE, // 1a: some kind of tape movement
CMD_UNK_1b, // 1b: unknown
CMD_DELTA_MOVE_REC, // 1c: move tape a given distance (optionally stop at 1st record) (?)
CMD_START_READ, // 1d: start record reading
CMD_DELTA_MOVE_IRG, // 1e: move tape a given distance (optionally stop at 1st IRG)
CMD_END_READ // 1f: stop reading
};
// Bits of status register
#define STATUS_HOLE_BIT 0 // Hole detected
#define STATUS_CART_OUT_BIT 1 // Cartridge out
#define STATUS_SFAIL_BIT 2 // Servo failure
#define STATUS_WPR_BIT 3 // Write protection
#define STATUS_GAP_BIT 4 // Gap detected
#define STATUS_TRACKB_BIT 5 // Track B selected
// *** Position of tape holes ***
// At beginning of tape:
// *START*
// |<-----24"----->|<---12"--->|<---12"--->|<-----24"----->|
// O O O O O O O
// |<->| |<->| |<->|
// 0.218" 0.218" 0.218"
// At end of tape:
// *END*
// |<-----24"----->|<---12"--->|<---12"--->|<-----24"----->|
// O O O O
//
static const hp_taco_device::tape_pos_t tape_holes[] = {
(hp_taco_device::tape_pos_t)(23.891 * TACH_TICKS_PER_INCH), // 24 - 0.218 / 2
(hp_taco_device::tape_pos_t)(24.109 * TACH_TICKS_PER_INCH), // 24 + 0.218 / 2
(hp_taco_device::tape_pos_t)(35.891 * TACH_TICKS_PER_INCH), // 36 - 0.218 / 2
(hp_taco_device::tape_pos_t)(36.109 * TACH_TICKS_PER_INCH), // 36 + 0.218 / 2
(hp_taco_device::tape_pos_t)(47.891 * TACH_TICKS_PER_INCH), // 48 - 0.218 / 2
(hp_taco_device::tape_pos_t)(48.109 * TACH_TICKS_PER_INCH), // 48 + 0.218 / 2
72 * TACH_TICKS_PER_INCH, // 72
1752 * TACH_TICKS_PER_INCH, // 1752
1776 * TACH_TICKS_PER_INCH, // 1776
1788 * TACH_TICKS_PER_INCH, // 1788
1800 * TACH_TICKS_PER_INCH // 1800
};
// Device type definition
const device_type HP_TACO = &device_creator<hp_taco_device>;
// Constructors
hp_taco_device::hp_taco_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname)
: device_t(mconfig, type, name, tag, owner, clock, shortname, __FILE__),
m_irq_handler(*this),
m_flg_handler(*this),
m_sts_handler(*this),
m_data_reg(0),
m_cmd_reg(0),
m_status_reg(0),
m_tach_reg(0),
m_checksum_reg(0),
m_timing_reg(0),
m_tape_pos(TAPE_INIT_POS)
{
}
hp_taco_device::hp_taco_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: device_t(mconfig, HP_TACO, "HP TACO", tag, owner, clock, "TACO", __FILE__),
m_irq_handler(*this),
m_flg_handler(*this),
m_sts_handler(*this),
m_data_reg(0),
m_cmd_reg(0),
m_status_reg(0),
m_tach_reg(0),
m_checksum_reg(0),
m_timing_reg(0),
m_tape_pos(TAPE_INIT_POS)
{
}
WRITE16_MEMBER(hp_taco_device::reg_w)
{
LOG(("wr R%u = %04x\n", 4 + offset , data));
// Any I/O activity clears IRQ
irq_w(false);
switch (offset) {
case 0:
// Data register
m_data_reg = data;
break;
case 1:
// Command register
start_cmd_exec(data & CMD_REG_MASK);
break;
case 2:
// Tachometer register
m_tach_reg = data;
break;
case 3:
// Timing register
m_timing_reg = data;
break;
}
}
READ16_MEMBER(hp_taco_device::reg_r)
{
UINT16 res = 0;
// Any I/O activity clears IRQ
irq_w(false);
switch (offset) {
case 0:
// Data register
res = m_data_reg;
break;
case 1:
// Command & status register
res = (m_cmd_reg & CMD_REG_MASK) | (m_status_reg & STATUS_REG_MASK);
break;
case 2:
// Tachometer register
res = m_tach_reg;
break;
case 3:
// Checksum register
res = m_checksum_reg;
m_checksum_reg = 0;
break;
}
LOG(("rd R%u = %04x\n", 4 + offset , res));
return res;
}
READ_LINE_MEMBER(hp_taco_device::flg_r)
{
return m_flg;
}
READ_LINE_MEMBER(hp_taco_device::sts_r)
{
return m_sts;
}
// device_start
void hp_taco_device::device_start()
{
m_irq_handler.resolve_safe();
m_flg_handler.resolve_safe();
m_sts_handler.resolve_safe();
save_item(NAME(m_data_reg));
save_item(NAME(m_cmd_reg));
save_item(NAME(m_status_reg));
save_item(NAME(m_tach_reg));
save_item(NAME(m_checksum_reg));
save_item(NAME(m_timing_reg));
save_item(NAME(m_irq));
save_item(NAME(m_flg));
save_item(NAME(m_sts));
save_item(NAME(m_tape_pos));
save_item(NAME(m_start_time));
m_tape_timer = timer_alloc(TAPE_TMR_ID);
}
// device_reset
void hp_taco_device::device_reset()
{
m_data_reg = 0;
m_cmd_reg = 0;
m_status_reg = 0;
m_tach_reg = 0;
m_checksum_reg = 0;
m_timing_reg = 0;
m_start_time = attotime::never;
m_irq = false;
m_flg = true;
m_irq_handler(false);
m_flg_handler(true);
set_error(false);
}
void hp_taco_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
switch (id) {
case TAPE_TMR_ID:
LOG(("Tape tmr @%g\n" , machine().time().as_double()));
switch (CMD_CODE(m_cmd_reg)) {
case CMD_MOVE:
// Generate an interrupt each time a hole is crossed (tape doesn't stop)
update_tape_pos();
m_tape_timer->adjust(time_to_target(next_hole(DIR_FWD(m_cmd_reg)) , SPEED_FAST(m_cmd_reg)));
BIT_SET(m_status_reg, STATUS_HOLE_BIT);
break;
case CMD_DELTA_MOVE_REC:
case CMD_DELTA_MOVE_IRG:
// Interrupt & stop at end of movement
stop_tape();
break;
default:
// Other commands: just raise irq
break;
}
irq_w(true);
break;
default:
break;
}
}
void hp_taco_device::irq_w(bool state)
{
if (state != m_irq) {
m_irq = state;
m_irq_handler(state);
LOG(("IRQ = %d\n" , state));
}
}
void hp_taco_device::set_error(bool state)
{
m_sts = !state;
m_sts_handler(m_sts);
LOG(("error = %d\n" , state));
}
bool hp_taco_device::check_for_errors(void)
{
// Is it an error when "status" flag is already reporting an error? Dunno...
if ((m_status_reg & STATUS_ERR_MASK) != 0) {
set_error(true);
return true;
} else {
return false;
}
}
unsigned hp_taco_device::speed_to_tick_freq(bool fast)
{
return fast ? TACH_FREQ_FAST : TACH_FREQ_SLOW;
}
void hp_taco_device::update_tape_pos(void)
{
attotime delta_time(machine().time() - m_start_time);
m_start_time = machine().time();
LOG(("delta_time = %g\n" , delta_time.as_double()));
// How many tachometer ticks has the tape moved?
unsigned delta_tach = (unsigned)(delta_time.as_ticks(speed_to_tick_freq(SPEED_FAST(m_cmd_reg))));
LOG(("delta_tach = %u\n" , delta_tach));
if (DIR_FWD(m_cmd_reg)) {
// Forward
m_tape_pos += delta_tach;
// In real life tape would unspool..
if (m_tape_pos > TAPE_LENGTH) {
m_tape_pos = TAPE_LENGTH;
LOG(("Tape unspooled at the end!\n"));
}
} else {
// Reverse
if (delta_tach >= m_tape_pos) {
m_tape_pos = 0;
LOG(("Tape unspooled at the start!\n"));
} else {
m_tape_pos -= delta_tach;
}
}
LOG(("Tape pos = %u\n" , m_tape_pos));
}
// Is there any hole in a given section of tape?
bool hp_taco_device::any_hole(tape_pos_t tape_pos_a , tape_pos_t tape_pos_b)
{
if (tape_pos_a > tape_pos_b) {
// Ensure A always comes before B
tape_pos_t tmp;
tmp = tape_pos_a;
tape_pos_a = tape_pos_b;
tape_pos_b = tmp;
}
for (tape_pos_t hole : tape_holes) {
if (tape_pos_a < hole && tape_pos_b >= hole) {
return true;
}
}
return false;
}
// Position of next hole tape will reach in a given direction
hp_taco_device::tape_pos_t hp_taco_device::next_hole(bool fwd) const
{
if (fwd) {
for (tape_pos_t hole : tape_holes) {
if (hole > m_tape_pos) {
LOG(("next hole fwd @%u = %u\n" , m_tape_pos , hole));
return hole;
}
}
// No more holes: will hit end of tape
return TAPE_LENGTH;
} else {
for (int i = (sizeof(tape_holes) / sizeof(tape_holes[ 0 ])) - 1; i >= 0; i--) {
if (tape_holes[ i ] < m_tape_pos) {
LOG(("next hole rev @%u = %u\n" , m_tape_pos , tape_holes[ i ]));
return tape_holes[ i ];
}
}
// No more holes: will hit start of tape
return 0;
}
}
attotime hp_taco_device::time_to_distance(tape_pos_t distance, bool fast)
{
// +1 for rounding
return attotime::from_ticks(distance + 1 , speed_to_tick_freq(fast));
}
attotime hp_taco_device::time_to_target(tape_pos_t target, bool fast) const
{
return time_to_distance(abs(target - m_tape_pos), fast);
}
void hp_taco_device::start_tape(void)
{
m_start_time = machine().time();
BIT_CLR(m_status_reg, STATUS_HOLE_BIT);
}
void hp_taco_device::stop_tape(void)
{
if (!m_start_time.is_never()) {
tape_pos_t tape_start_pos = m_tape_pos;
update_tape_pos();
if (any_hole(tape_start_pos , m_tape_pos)) {
// Crossed one or more holes
BIT_SET(m_status_reg , STATUS_HOLE_BIT);
}
m_start_time = attotime::never;
}
m_tape_timer->reset();
}
void hp_taco_device::start_cmd_exec(UINT16 new_cmd_reg)
{
LOG(("Cmd = %02x\n" , CMD_CODE(new_cmd_reg)));
attotime cmd_duration = attotime::never;
// Should irq be raised anyway when already in error condition? Here we do nothing.
switch (CMD_CODE(new_cmd_reg)) {
case CMD_CLEAR:
set_error(false);
BIT_CLR(m_status_reg, STATUS_HOLE_BIT);
// This is a special command: it doesn't raise IRQ at completion and it
// doesn't replace the current command, if any.
return;
case CMD_STOP:
stop_tape();
cmd_duration = attotime::from_usec(QUICK_CMD_USEC);
break;
case CMD_SET_TRACK:
if (!check_for_errors()) {
if (CMD_OPT(new_cmd_reg)) {
BIT_SET(m_status_reg, STATUS_TRACKB_BIT);
} else {
BIT_CLR(m_status_reg, STATUS_TRACKB_BIT);
}
cmd_duration = attotime::from_usec(QUICK_CMD_USEC);
}
break;
case CMD_MOVE:
stop_tape();
if (!check_for_errors()) {
start_tape();
cmd_duration = time_to_target(next_hole(DIR_FWD(new_cmd_reg)) , SPEED_FAST(new_cmd_reg));
}
break;
case CMD_DELTA_MOVE_REC:
case CMD_DELTA_MOVE_IRG:
// TODO: record/irg detection
stop_tape();
if (!check_for_errors()) {
start_tape();
cmd_duration = time_to_distance(0x10000U - m_tach_reg , SPEED_FAST(new_cmd_reg));
}
break;
default:
LOG(("Unrecognized command\n"));
return;
}
m_tape_timer->adjust(cmd_duration);
m_cmd_reg = new_cmd_reg;
}

View File

@ -0,0 +1,93 @@
// license:BSD-3-Clause
// copyright-holders:F. Ulivi
/*********************************************************************
hp_taco.h
HP TApe COntroller (5006-3012)
*********************************************************************/
#ifndef __HP_TACO_H__
#define __HP_TACO_H__
#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:
// 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);
typedef UINT32 tape_pos_t;
protected:
// device-level overrides
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_flg_handler;
devcb_write_line m_sts_handler;
// Registers
UINT16 m_data_reg;
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;
// Tape position
tape_pos_t m_tape_pos;
attotime m_start_time;
// Timers
emu_timer *m_tape_timer;
void irq_w(bool state);
void set_error(bool state);
bool check_for_errors(void);
static unsigned speed_to_tick_freq(bool fast);
void update_tape_pos(void);
static bool any_hole(UINT32 tape_pos_a , UINT32 tape_pos_b);
UINT32 next_hole(bool fwd) const;
static attotime time_to_distance(UINT32 distance, bool fast);
attotime time_to_target(UINT32 target, bool fast) const;
void start_tape(void);
void stop_tape(void);
void start_cmd_exec(UINT16 new_cmd_reg);
};
// device type definition
extern const device_type HP_TACO;
#endif /* __HP_TACO_H__ */

View File

@ -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