-machine/mm5740.cpp: Added repeat input. (#11352)

-heathkit/tlb.cpp: Hooked up repeat key and fixed interrupt state calculation.
This commit is contained in:
Mark Garlanger 2023-07-04 14:04:06 -05:00 committed by GitHub
parent ccd82f0a56
commit d0f793242f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 136 additions and 83 deletions

View File

@ -43,7 +43,7 @@ const tiny_rom_entry *mm5740_device::device_rom_region() const
// mm5740_device - constructor
//-------------------------------------------------
mm5740_device::mm5740_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
mm5740_device::mm5740_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
device_t(mconfig, MM5740, tag, owner, clock),
m_read_x(*this, 0x3ff),
m_read_shift(*this, 0),
@ -51,13 +51,12 @@ mm5740_device::mm5740_device(const machine_config &mconfig, const char *tag, dev
m_write_data_ready(*this),
m_rom(*this, "internal")
{
std::fill(std::begin(m_x_mask), std::end(m_x_mask), 0);
}
uint32_t mm5740_device::calc_effective_clock_key_debounce(uint32_t capacitance)
u32 mm5740_device::calc_effective_clock_key_debounce(u32 capacitance)
{
// calculate key debounce based on capacitance in pF
uint32_t key_debounce_msec = capacitance / 125;
u32 key_debounce_msec = capacitance / 125;
if (key_debounce_msec == 0)
{
key_debounce_msec = 1;
@ -72,22 +71,21 @@ uint32_t mm5740_device::calc_effective_clock_key_debounce(uint32_t capacitance)
void mm5740_device::device_start()
{
std::fill(std::begin(m_x_mask), std::end(m_x_mask), 0);
m_b = -1;
m_repeat = false;
m_last_repeat = false;
// allocate timers
m_scan_timer = timer_alloc(FUNC(mm5740_device::perform_scan), this);
m_scan_timer->adjust(attotime::from_hz(clock()), 0, attotime::from_hz(clock()));
// state saving
save_item(NAME(m_b));
save_item(NAME(m_offset));
save_item(NAME(m_x_mask));
}
//-------------------------------------------------
// device_start - device-specific reset
//-------------------------------------------------
void mm5740_device::device_reset()
{
save_item(NAME(m_repeat));
save_item(NAME(m_last_repeat));
}
//-------------------------------------------------
@ -100,7 +98,12 @@ TIMER_CALLBACK_MEMBER(mm5740_device::perform_scan)
for (int x = 0; x < 9; x++)
{
uint16_t data = m_read_x[x]() ^ 0x3ff;
u16 data = m_read_x[x]() ^ 0x3ff;
if (data)
{
ako = true;
}
if ((data ^ m_x_mask[x]) == 0)
{
@ -110,41 +113,55 @@ TIMER_CALLBACK_MEMBER(mm5740_device::perform_scan)
for (int y = 0; y < 10; y++)
{
u16 offset = x * 10 + y;
if (BIT(data, y))
{
uint8_t *rom = m_rom->base();
uint16_t offset = x*10 + y;
u8 *rom = m_rom->base();
// Common portion
uint16_t common = (uint16_t) rom[offset];
u16 common = (u16)rom[offset];
offset += (((m_read_shift() ? 1: 0) + (m_read_control() ? 2: 0)) + 1) * 90;
u16 uniq_offset = offset + ((((m_read_shift() ? 1 : 0) + (m_read_control() ? 2 : 0)) + 1) * 90);
// Unique portion based on shift/ctrl keys.
uint8_t uniq = rom[offset];
u8 uniq = rom[uniq_offset];
uint16_t b = (((common & 0x10) << 4) | ((uniq & 0x0f) << 4) | (common & 0x0f)) ^ 0x1ff;
ako = true;
u16 b = (((common & 0x10) << 4) | ((uniq & 0x0f) << 4) | (common & 0x0f)) ^ 0x1ff;
// Check for a new keypress
if (!BIT(m_x_mask[x], y))
{
m_x_mask[x] |= (1 << y);
if (m_b != b)
{
m_b = b;
m_offset = offset;
m_write_data_ready(ASSERT_LINE);
return;
}
}
}
else // key released, unmark it from the "down" info
else
{
// key released, unmark it from the "down" info
m_x_mask[x] &= ~(1 << y);
if (m_offset == offset)
{
m_write_data_ready(CLEAR_LINE);
m_b = -1;
}
}
}
}
if ((m_repeat) && (!m_last_repeat) && (m_b != -1))
{
m_write_data_ready(ASSERT_LINE);
}
m_last_repeat = m_repeat;
if (!ako)
{
m_write_data_ready(CLEAR_LINE);
@ -152,12 +169,16 @@ TIMER_CALLBACK_MEMBER(mm5740_device::perform_scan)
}
}
void mm5740_device::repeat_line_w(int state)
{
m_repeat = (state == ASSERT_LINE);
}
//-------------------------------------------------
// b_r -
//-------------------------------------------------
uint16_t mm5740_device::b_r()
u16 mm5740_device::b_r()
{
m_write_data_ready(CLEAR_LINE);
return m_b;

View File

@ -1,10 +1,10 @@
// license:BSD-3-Clause
// copyright-holders: R. Belmont
// copyright-holders: R. Belmont, Mark Garlanger
/**********************************************************************
MM5740 Keyboard Encoder emulation
**********************************************************************
**********************************************************************
_____ _____
B3 1 |* \_/ | 40 B4
Vll 2 | | 39 B9
@ -27,13 +27,14 @@
Control 19 | | 22 Y10
Shift Lock I/O 20 |_____________| 21 Shift
Name Pin No. Function
----------------------------------------------------------------------
X1-X9 4-12 Output - Drives the key switch matrix.
Y1-Y10 22-31 Inputs - connect to the X drive lines with
the key switch matrix.
the key switch matrix.
B1-B9 1,33-40 Tri-stated data outputs.
@ -44,10 +45,10 @@ Data Strobe Control 14 Input to control data strobe output pulse width
Output Enable 15 Input to control the chip's TRI-STATE output
Repeat 16 Each cycle of this signal will issue
a new data strobe for the pressed key.
a new data strobe for the pressed key.
Key-Bounce Mask 17 Use capacitor on this chip to provide
key debouncing
key debouncing
Shift 21 Shift key pressed
@ -63,12 +64,9 @@ Vll 2 Ground
Vgg 18 -12V
**********************************************************************/
/* TODO:
Support Key-bounce mask
Support Repeat function
Support shift lock
Support additional internal ROMs
*/
@ -78,33 +76,26 @@ Vgg 18 -12V
#pragma once
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
// ======================> mm5740_device
class mm5740_device : public device_t
{
public:
// construction/destruction
mm5740_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
mm5740_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
// public interface
uint16_t b_r();
u16 b_r();
template <unsigned N> auto x_cb() { return m_read_x[N - 1].bind(); }
auto shift_cb() { return m_read_shift.bind(); }
auto control_cb() { return m_read_control.bind(); }
auto data_ready_cb() { return m_write_data_ready.bind(); }
static uint32_t calc_effective_clock_key_debounce(uint32_t capacitance);
void repeat_line_w(int state);
static u32 calc_effective_clock_key_debounce(u32 capacitance);
protected:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
virtual const tiny_rom_entry *device_rom_region() const override;
@ -116,14 +107,17 @@ private:
devcb_read_line m_read_control;
devcb_write_line m_write_data_ready;
required_memory_region m_rom; // Internal ROM
required_memory_region m_rom; // Internal ROM
int m_b; // output buffer
s32 m_b; // output buffer
u16 m_offset; // last key pressed (without shift/ctrl modifiers)
int m_x_mask[9]; // mask of what keys are down
u16 m_x_mask[9]; // mask of what keys are down
bool m_repeat; // state of the 'repeat' input.
bool m_last_repeat; // state of the repeat input on the last scan.
// timers
emu_timer *m_scan_timer; // keyboard scan timer
emu_timer *m_scan_timer; // keyboard scan timer
};

View File

@ -454,7 +454,7 @@ void h89_state::h89(machine_config & config)
HEATH_TLB(config, m_tlb);
// Connect the console port on CPU board to serial port on TLB
m_console->out_tx_callback().set(m_tlb, FUNC(heath_tlb_device::cb1_w));
m_console->out_tx_callback().set(m_tlb, FUNC(heath_tlb_device::serial_in_w));
m_tlb->serial_data_callback().set(m_console, FUNC(ins8250_uart_device::rx_w));
m_tlb->reset_cb().set(FUNC(h89_state::reset_line));

View File

@ -19,7 +19,6 @@
TODO:
- determine why ULTRA ROM's self-diag (ESC |) fails for the ROM and
scratchpad memory
- when pressing "REPEAT", the other pressed key should repeatedly trigger
****************************************************************************/
/***************************************************************************
@ -42,12 +41,12 @@
----------------------------------------------------
0x00 Power-up configuration (primary - SW401)
0x20 Power-up configuration (secondary - SW402)
0x40 ACE (communications)
0x60 CRT controller
0x80 Keyboard encoder
0x40 INS8250 ACE (communications)
0x60 MC6845 CRT controller
0x80 MM5740 Keyboard encoder
0xA0 Keyboard status
0xC0 Key click enable
0xE0 Bell enable
0xC0 Trigger key click
0xE0 Trigger bell
****************************************************************************/
@ -93,13 +92,14 @@ heath_tlb_device::heath_tlb_device(const machine_config &mconfig, device_type ty
m_p_chargen(*this, "chargen"),
m_mm5740(*this, "mm5740"),
m_kbdrom(*this, "keyboard"),
m_kbspecial(*this, "MODIFIERS")
m_kbspecial(*this, "MODIFIERS"),
m_repeat_clock(*this, "repeatclock")
{
}
void heath_tlb_device::checkBeepState()
void heath_tlb_device::check_beep_state()
{
if (!m_keyclickactive && !m_bellactive)
if (!m_key_click_active && !m_bell_active)
{
m_beep->set_state(0);
}
@ -107,16 +107,16 @@ void heath_tlb_device::checkBeepState()
TIMER_CALLBACK_MEMBER(heath_tlb_device::key_click_off)
{
m_keyclickactive = false;
m_key_click_active = false;
checkBeepState();
check_beep_state();
}
TIMER_CALLBACK_MEMBER(heath_tlb_device::bell_off)
{
m_bellactive = false;
m_bell_active = false;
checkBeepState();
check_beep_state();
}
void heath_tlb_device::mem_map(address_map &map)
@ -152,6 +152,7 @@ static constexpr uint8_t KB_STATUS_SHIFT_KEYS_MASK = 0x01;
static constexpr uint8_t KB_STATUS_CAPS_LOCK_MASK = 0x02;
static constexpr uint8_t KB_STATUS_BREAK_KEY_MASK = 0x04;
static constexpr uint8_t KB_STATUS_ONLINE_KEY_MASK = 0x08;
static constexpr uint8_t KB_STATUS_CONTROL_KEY_MASK = 0x10;
static constexpr uint8_t KB_STATUS_REPEAT_KEYS_MASK = 0x40;
static constexpr uint8_t KB_STATUS_KEYBOARD_STROBE_MASK = 0x80;
@ -159,18 +160,22 @@ void heath_tlb_device::device_start()
{
save_item(NAME(m_transchar));
save_item(NAME(m_strobe));
save_item(NAME(m_keyclickactive));
save_item(NAME(m_bellactive));
save_item(NAME(m_key_click_active));
save_item(NAME(m_bell_active));
save_item(NAME(m_reset_pending));
save_item(NAME(m_right_shift));
save_item(NAME(m_reset_key));
save_item(NAME(m_keyboard_irq_raised));
save_item(NAME(m_serial_irq_raised));
m_strobe = false;
m_keyclickactive = false;
m_bellactive = false;
m_key_click_active = false;
m_bell_active = false;
m_reset_pending = false;
m_right_shift = false;
m_reset_key = false;
m_keyboard_irq_raised = false;
m_serial_irq_raised = false;
m_key_click_timer = timer_alloc(FUNC(heath_tlb_device::key_click_off), this);
m_bell_timer = timer_alloc(FUNC(heath_tlb_device::bell_off), this);
@ -179,15 +184,15 @@ void heath_tlb_device::device_start()
void heath_tlb_device::device_reset()
{
m_strobe = false;
m_keyclickactive = false;
m_bellactive = false;
m_key_click_active = false;
m_bell_active = false;
}
void heath_tlb_device::key_click_w(uint8_t data)
{
// Keyclick - 6 mSec
m_beep->set_state(1);
m_keyclickactive = true;
m_key_click_active = true;
m_key_click_timer->adjust(attotime::from_msec(6));
}
@ -195,7 +200,7 @@ void heath_tlb_device::bell_w(uint8_t data)
{
// Bell (^G) - 200 mSec
m_beep->set_state(1);
m_bellactive = true;
m_bell_active = true;
m_bell_timer->adjust(attotime::from_msec(200));
}
@ -223,7 +228,8 @@ uint16_t heath_tlb_device::translate_mm5740_b(uint16_t b)
uint8_t heath_tlb_device::kbd_key_r()
{
m_maincpu->set_input_line(INPUT_LINE_IRQ0, CLEAR_LINE);
m_keyboard_irq_raised = false;
set_irq_line();
m_strobe = false;
// high bit is for control key pressed, this is handled in the ROM,
@ -257,7 +263,7 @@ int heath_tlb_device::mm5740_shift_r()
int heath_tlb_device::mm5740_control_r()
{
return (m_kbspecial->read() & 0x10) ? CLEAR_LINE : ASSERT_LINE;
return (m_kbspecial->read() & KB_STATUS_CONTROL_KEY_MASK) ? CLEAR_LINE : ASSERT_LINE;
}
void heath_tlb_device::mm5740_data_ready_w(int state)
@ -268,10 +274,23 @@ void heath_tlb_device::mm5740_data_ready_w(int state)
m_transchar = decode[translate_mm5740_b(m_mm5740->b_r())];
m_strobe = true;
m_maincpu->set_input_line(INPUT_LINE_IRQ0, ASSERT_LINE);
m_keyboard_irq_raised = true;
set_irq_line();
}
}
void heath_tlb_device::serial_irq_w(int state)
{
m_serial_irq_raised = state != CLEAR_LINE;
set_irq_line();
}
void heath_tlb_device::set_irq_line()
{
m_maincpu->set_input_line(INPUT_LINE_IRQ0,
(m_keyboard_irq_raised || m_serial_irq_raised) ? ASSERT_LINE : CLEAR_LINE);
}
void heath_tlb_device::check_for_reset()
{
if (m_reset_key && m_right_shift)
@ -303,6 +322,12 @@ void heath_tlb_device::right_shift_w(int state)
check_for_reset();
}
void heath_tlb_device::repeat_key_w(int state)
{
// when repeat key pressed, set duty cycle to 0.5, else 0.
m_repeat_clock->set_duty_cycle(state == CLEAR_LINE ? 0.5 : 0);
}
MC6845_UPDATE_ROW(heath_tlb_device::crtc_update_row)
{
rgb_t const *const palette = m_palette->palette()->entry_list_raw();
@ -384,7 +409,7 @@ static INPUT_PORTS_START( tlb )
PORT_BIT(0x008, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("OffLine") PORT_CODE(KEYCODE_F12) PORT_TOGGLE
PORT_BIT(0x010, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("CTRL") PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_MAMEKEY(LCONTROL))
PORT_BIT(0x020, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("LeftShift") PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1)
PORT_BIT(0x040, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Repeat") PORT_CODE(KEYCODE_LALT)
PORT_BIT(0x040, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Repeat") PORT_CODE(KEYCODE_RALT) PORT_WRITE_LINE_MEMBER(heath_tlb_device, repeat_key_w)
// bit 7 - 0x080 is low if a key is pressed
PORT_BIT(0x100, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("RightShift") PORT_CODE(KEYCODE_RSHIFT) PORT_WRITE_LINE_MEMBER(heath_tlb_device, right_shift_w)
PORT_BIT(0x200, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Reset") PORT_CODE(KEYCODE_F10) PORT_WRITE_LINE_MEMBER(heath_tlb_device, reset_key_w)
@ -749,7 +774,7 @@ void heath_tlb_device::serial_out_b(uint8_t data)
m_write_sd(data);
}
void heath_tlb_device::cb1_w(int state)
void heath_tlb_device::serial_in_w(int state)
{
m_ace->rx_w(state);
}
@ -775,11 +800,12 @@ void heath_tlb_device::device_add_mconfig(machine_config &config)
m_crtc->set_show_border_area(true);
m_crtc->set_char_width(8);
m_crtc->set_update_row_callback(FUNC(heath_tlb_device::crtc_update_row));
m_crtc->out_vsync_callback().set_inputline(m_maincpu, INPUT_LINE_NMI); // frame pulse
// frame pulse
m_crtc->out_vsync_callback().set_inputline(m_maincpu, INPUT_LINE_NMI);
// serial port
INS8250(config, m_ace, INS8250_CLOCK);
m_ace->out_int_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ0);
m_ace->out_int_callback().set(FUNC(heath_tlb_device::serial_irq_w));
m_ace->out_tx_callback().set(FUNC(heath_tlb_device::serial_out_b));
// keyboard
@ -800,6 +826,10 @@ void heath_tlb_device::device_add_mconfig(machine_config &config)
// sound hardware
SPEAKER(config, "mono").front_center();
BEEP(config, m_beep, H19_BEEP_FRQ).add_route(ALL_OUTPUTS, "mono", 0.05);
CLOCK(config, m_repeat_clock, 40);
m_repeat_clock->set_duty_cycle(0);
m_repeat_clock->signal_handler().set(m_mm5740, FUNC(mm5740_device::repeat_line_w));
}
heath_super19_tlb_device::heath_super19_tlb_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :

View File

@ -12,6 +12,7 @@
#pragma once
#include "cpu/z80/z80.h"
#include "machine/clock.h"
#include "machine/ins8250.h"
#include "machine/mm5740.h"
#include "sound/beep.h"
@ -29,10 +30,12 @@ public:
auto serial_data_callback() { return m_write_sd.bind(); }
auto reset_cb() { return m_reset.bind(); }
void cb1_w(int state);
void serial_in_w(int state);
void reset_key_w(int state);
void right_shift_w(int state);
void repeat_key_w(int state);
void serial_irq_w(int state);
protected:
heath_tlb_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock = 0);
@ -49,14 +52,16 @@ protected:
required_device<cpu_device> m_maincpu;
private:
void set_irq_line();
void check_for_reset();
void key_click_w(uint8_t data);
void bell_w(uint8_t data);
void check_for_reset();
uint8_t kbd_key_r();
uint8_t kbd_flags_r();
uint16_t translate_mm5740_b(uint16_t b);
void checkBeepState();
void check_beep_state();
void serial_out_b(uint8_t data);
@ -80,18 +85,21 @@ private:
required_device<ins8250_device> m_ace;
required_device<beep_device> m_beep;
required_shared_ptr<uint8_t> m_p_videoram;
required_region_ptr<u8> m_p_chargen;
required_region_ptr<uint8_t> m_p_chargen;
required_device<mm5740_device> m_mm5740;
required_memory_region m_kbdrom;
required_ioport m_kbspecial;
required_device<clock_device> m_repeat_clock;
uint8_t m_transchar;
bool m_strobe;
bool m_keyclickactive;
bool m_bellactive;
bool m_key_click_active;
bool m_bell_active;
bool m_reset_pending;
bool m_right_shift;
bool m_reset_key;
bool m_keyboard_irq_raised;
bool m_serial_irq_raised;
};
class heath_super19_tlb_device : public heath_tlb_device