summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/drivers/hp2640.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/drivers/hp2640.cpp')
-rw-r--r--src/mame/drivers/hp2640.cpp431
1 files changed, 392 insertions, 39 deletions
diff --git a/src/mame/drivers/hp2640.cpp b/src/mame/drivers/hp2640.cpp
index e223b7b51e6..e79a1563034 100644
--- a/src/mame/drivers/hp2640.cpp
+++ b/src/mame/drivers/hp2640.cpp
@@ -5,12 +5,65 @@
// Driver for HP2640-series terminals
// **********************************
//
-// This is WIP: lot of things still missing
+// HP264x terminals are built around a few common elements:
+// - Chassis with a passive card cage and power supply. Cards share a common bus
+// with a daisy-chained priority order (i.e. cards closer to power supply have
+// higher priority in accessing the bus). The bus also distributes a 4.9152 MHz
+// system clock.
+// - White phosphor CRT (with its unusual 2:1 ratio) and the related drive board
+// - Keyboard
+// The "personality" in each version is in the set of cards installed in
+// the card cage (and in a few minor differences of the common elements).
+// This driver emulates the HP2645A model, as composed of the following cards:
+// - 02640-60123 Keyboard interface
+// - 02640-60112 Display control
+// - 02640-60088 Display timing
+// - 02640-60124 Display extended DMA
+// - 02640-60024 Display enhancement
+// - 02640-60209 CPU
+// - 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
+//
+// The following table summarizes the emulated character sets.
+//
+// | Char. set | Description | No. of chars | ROMs | Type |
+// |-----------+----------------+--------------+-----------+-------------------|
+// | 0 | Std ASCII set | 128 | 1816-0612 | Alphanumeric |
+// | | | | 1816-0613 | |
+// | 1 | Math symbols | 64 | 1816-0642 | Alphanumeric |
+// | 2 | Line drawing | 64 | 1816-1417 | 8-bit microvector |
+// | 3 | Big characters | 64 | 1816-1425 | 8-bit microvector |
+//
+// All characters are rendered in a 9x15 cell.
+// Fonts are rendered in different ways according to type: alphanumeric fonts
+// take advantage of half-pixel shifting for aesthetic improvement, microvector fonts
+// are rendered by mapping 8 bits to 9 pixels (bit 0 is displayed twice).
+// Earlier versions of display hw used weird 9-bit PROMs for microvector fonts.
+// Then, luckily, HP wised up and reverted to 8-bit memories.
+//
+// All non-volatile settings of this terminal are "stored" in mechanical switches
+// and not in non-volatile memories (they were probably too expensive/limited/unreliable
+// back then).
+// There are 3 switches in a corner of the keyboard (data comm switches) and 24 option
+// switches (named A to Z) on the keyboard interface PCB.
+//
+// Notes:
+// - Speed of the CPU is not accurately emulated. The effects of bus sharing by
+// video DMA and CPU are not taken into account.
+// - 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"
#include "cpu/i8085/i8085.h"
#include "machine/timer.h"
+#include "bus/rs232/rs232.h"
+#include "machine/ay31015.h"
+#include "sound/beep.h"
+#include "speaker.h"
#include "hp2640.lh"
@@ -57,6 +110,8 @@ constexpr unsigned VIDEO_CHAR_HEIGHT = 15;
constexpr uint16_t START_DMA_ADDR = 0xffff;
constexpr unsigned MAX_DMA_CYCLES = 450;
constexpr unsigned CURSOR_BLINK_INH_MS = 110;
+constexpr unsigned BEEP_FREQUENCY = 650;
+constexpr unsigned BEEP_DURATION_MS = 100;
// ************
// hp2645_state
@@ -89,20 +144,36 @@ public:
DECLARE_WRITE8_MEMBER(cy_w);
TIMER_DEVICE_CALLBACK_MEMBER(timer_cursor_blink_inh);
+ DECLARE_READ8_MEMBER(async_data_r);
+ DECLARE_READ8_MEMBER(async_status_r);
+ DECLARE_WRITE8_MEMBER(async_control_w);
+ DECLARE_WRITE8_MEMBER(async_data_w);
+ DECLARE_WRITE8_MEMBER(async_status_change);
+ DECLARE_WRITE_LINE_MEMBER(async_txd_w);
+
+ TIMER_DEVICE_CALLBACK_MEMBER(timer_beep_exp);
protected:
required_device<i8080a_cpu_device> m_cpu;
required_device<timer_device> m_timer_10ms;
required_ioport_array<4> m_io_key;
+ required_ioport m_io_comm;
+ required_ioport m_io_sw_ah;
+ required_ioport m_io_sw_jr;
+ required_ioport m_io_sw_sz;
required_device<screen_device> m_screen;
required_device<palette_device> m_palette;
required_device<timer_device> m_timer_cursor_blink_inh;
+ required_device<rs232_port_device> m_rs232;
+ required_device<ay31015_device> m_uart;
+ required_device<beep_device> m_beep;
+ required_device<timer_device> m_timer_beep;
uint8_t m_mode_byte;
bool m_timer_irq;
bool m_datacom_irq;
// Character generators
- required_region_ptr<uint8_t> m_chargen0;
+ required_region_ptr_array<uint8_t , 4> m_chargen;
// Video DMA
struct line_buffer {
@@ -128,11 +199,16 @@ protected:
uint8_t m_cursor_y;
bool m_cursor_blink_inh;
+ // Async line interface
+ uint8_t m_async_control;
+
void update_irq();
uint8_t video_dma_get();
void video_load_buffer(bool buff_idx , unsigned& idx , uint8_t ch , bool iv , uint8_t attrs);
void video_fill_buffer(bool buff_idx , unsigned max_cycles);
void video_render_buffer(unsigned video_scanline , unsigned line_in_row , bool buff_idx , bool cyen);
+ void update_async_control(uint8_t new_control);
+ void update_async_irq();
};
hp2645_state::hp2645_state(const machine_config &mconfig, device_type type, const char *tag)
@@ -140,10 +216,18 @@ hp2645_state::hp2645_state(const machine_config &mconfig, device_type type, cons
m_cpu(*this , "cpu"),
m_timer_10ms(*this , "timer_10ms"),
m_io_key(*this , "KEY%u" , 0),
+ m_io_comm(*this , "comm"),
+ m_io_sw_ah(*this , "sw_ah"),
+ m_io_sw_jr(*this , "sw_jr"),
+ m_io_sw_sz(*this , "sw_sz"),
m_screen(*this , "screen"),
m_palette(*this , "palette"),
m_timer_cursor_blink_inh(*this , "timer_cursor_blink_inh"),
- m_chargen0(*this , "chargen0")
+ m_rs232(*this , "rs232"),
+ m_uart(*this , "uart"),
+ m_beep(*this , "beep"),
+ m_timer_beep(*this , "timer_beep"),
+ m_chargen(*this , "chargen%u" , 0)
{
}
@@ -164,6 +248,17 @@ void hp2645_state::machine_reset()
m_timer_10ms->reset();
update_irq();
m_dma_on = true;
+ m_uart->set_input_pin(AY31015_XR , 1);
+ m_uart->set_input_pin(AY31015_SWE , 0);
+ m_uart->set_input_pin(AY31015_CS , 1);
+ m_uart->set_input_pin(AY31015_NB2 , 1);
+ m_async_control = 0;
+ m_uart->set_receiver_clock(0);
+ m_uart->set_transmitter_clock(0);
+ update_async_control(0x00);
+ m_rs232->write_dtr(0);
+ async_txd_w(0);
+ m_beep->set_state(0);
}
IRQ_CALLBACK_MEMBER(hp2645_state::irq_callback)
@@ -181,7 +276,7 @@ IRQ_CALLBACK_MEMBER(hp2645_state::irq_callback)
// RST 0: should never happen (TM)
res = 0xc7;
}
-
+ LOG("IRQ ACK %02x\n" , res);
return res;
}
@@ -217,38 +312,49 @@ READ8_MEMBER(hp2645_state::kb_r)
WRITE8_MEMBER(hp2645_state::kb_prev_w)
{
+ // This port is used to set the threshold in key sense circuit for hysteresis.
+ // We can safely ignore all writes.
}
WRITE8_MEMBER(hp2645_state::kb_reset_w)
{
+ // TODO: enabled/disable CPU reset
}
READ8_MEMBER(hp2645_state::switches_ah_r)
{
- // TODO:
- return 0;
+ uint8_t res = m_io_sw_ah->read();
+ LOG("SW AH=%02x\n" , res);
+ return res;
}
READ8_MEMBER(hp2645_state::switches_jr_r)
{
- // TODO:
- return 0;
+ uint8_t res = m_io_sw_jr->read();
+ LOG("SW JR=%02x\n" , res);
+ return res;
}
READ8_MEMBER(hp2645_state::switches_sz_r)
{
- // TODO:
- return 0;
+ uint8_t res = m_io_sw_sz->read();
+ LOG("SW SZ=%02x\n" , res);
+ return res;
}
READ8_MEMBER(hp2645_state::datacomm_sw_r)
{
- // TODO:
- return 0;
+ uint8_t res = m_io_comm->read();
+ LOG("COM SW=%02x\n" , res);
+ return res;
}
WRITE8_MEMBER(hp2645_state::kb_led_w)
{
+ if (BIT(data , 7)) {
+ m_beep->set_state(1);
+ m_timer_beep->adjust(attotime::from_msec(BEEP_DURATION_MS));
+ }
// TODO:
LOG("LED = %02x\n" , data);
}
@@ -322,6 +428,70 @@ TIMER_DEVICE_CALLBACK_MEMBER(hp2645_state::timer_cursor_blink_inh)
m_cursor_blink_inh = false;
}
+READ8_MEMBER(hp2645_state::async_data_r)
+{
+ uint8_t res = m_uart->get_received_data();
+ m_uart->set_input_pin(AY31015_RDAV , 0);
+ LOG("ASYNC RX=%02x\n" , res);
+ // Update datacomm IRQ
+ update_async_irq();
+ return res;
+}
+
+READ8_MEMBER(hp2645_state::async_status_r)
+{
+ uint8_t res = 0;
+
+ if (m_uart->get_output_pin(AY31015_DAV)) {
+ BIT_SET(res, 0);
+ }
+ if (m_uart->get_output_pin(AY31015_TBMT)) {
+ BIT_SET(res, 1);
+ }
+ if (m_uart->get_output_pin(AY31015_OR)) {
+ BIT_SET(res, 2);
+ }
+ if (m_uart->get_output_pin(AY31015_PE)) {
+ BIT_SET(res, 3);
+ }
+ if (m_rs232->dcd_r()) {
+ BIT_SET(res, 4);
+ }
+ if (m_rs232->cts_r()) {
+ BIT_SET(res, 5);
+ }
+ // Secondary ch. receive always 1
+ BIT_SET(res, 6);
+ LOG("ASYNC ST=%02x\n" , res);
+ return res;
+}
+
+WRITE8_MEMBER(hp2645_state::async_control_w)
+{
+ update_async_control(data);
+}
+
+WRITE8_MEMBER(hp2645_state::async_data_w)
+{
+ LOG("ASYNC TX=%02x\n" , data);
+ m_uart->set_transmit_data(data);
+}
+
+WRITE8_MEMBER(hp2645_state::async_status_change)
+{
+ update_async_irq();
+}
+
+WRITE_LINE_MEMBER(hp2645_state::async_txd_w)
+{
+ m_rs232->write_txd(!BIT(m_async_control , 6) && m_uart->get_output_pin(AY31015_SO));
+}
+
+TIMER_DEVICE_CALLBACK_MEMBER(hp2645_state::timer_beep_exp)
+{
+ m_beep->set_state(0);
+}
+
void hp2645_state::update_irq()
{
bool state = (m_datacom_irq && !BIT(m_mode_byte , 4)) ||
@@ -445,56 +615,113 @@ void hp2645_state::video_render_buffer(unsigned video_scanline , unsigned line_i
cursor_blink = BIT(fn_12 , 0);
}
- // TODO: incomplete
for (unsigned i = 0 , x_left = 0; i < VIDEO_VIS_COLS; i++ , x_left += VIDEO_CHAR_WIDTH * 2) {
uint8_t ch = m_buffers[ buff_idx ].m_chars[ i ];
bool iv = BIT(ch , 7);
BIT_CLR(ch, 7);
uint8_t attrs = m_buffers[ buff_idx ].m_attrs[ i ];
-
+ uint8_t char_set = (attrs >> 4) & 3;
uint16_t ch_addr = ch & 0x1f;
if (BIT(ch , 6)) {
BIT_SET(ch_addr, 5);
}
- if ((ch <= 0x1f) || (ch >= 0x60)) {
+ uint8_t byte;
+ if (char_set == 0 && ((ch <= 0x1f) || (ch >= 0x60))) {
BIT_SET(ch_addr, 6);
}
- uint8_t byte = m_chargen0[ (ch_addr << 4) + line_in_row ];
- uint32_t pixels;
+ if (char_set == 0 || ch >= 0x20) {
+ byte = ~m_chargen[ char_set ][ (ch_addr << 4) + line_in_row ];
+ } else {
+ byte = 0;
+ }
+ uint16_t pixels_e;
+ uint16_t pixels_o;
+ bool microvector = (char_set == 2) || (char_set == 3);
+
if (cyen && (line_in_row == 11 || line_in_row == 12) && i == m_cursor_x) {
- pixels = cursor_blink ? ~0 : 0;
+ pixels_e = pixels_o = cursor_blink ? ~0 : 0;
} else if (BIT(fn_12 , 1) && BIT(attrs , 0)) {
- pixels = 0;
+ pixels_e = pixels_o = 0;
} else if (line_in_row == 11 && BIT(attrs , 2)) {
- pixels = ~0;
+ pixels_e = pixels_o = ~0;
+ } else if (microvector) {
+ pixels_e = pixels_o = uint16_t(byte) << 1;
+ // Copy b0
+ if (BIT(pixels_e , 1)) {
+ BIT_SET(pixels_e, 0);
+ BIT_SET(pixels_o, 0);
+ }
} else {
- pixels = uint32_t((byte >> 1) ^ 0x7f);
- pixels = ((pixels & 0x40) << 8) |
- ((pixels & 0x20) << 7) |
- ((pixels & 0x10) << 6) |
- ((pixels & 0x08) << 5) |
- ((pixels & 0x04) << 4) |
- ((pixels & 0x02) << 3) |
- ((pixels & 0x01) << 2);
- pixels |= (pixels << 1);
- if (!BIT(byte , 0)) {
- pixels <<= 1;
- if (BIT(pixels , 16)) {
- BIT_SET(pixels, 17);
+ bool half_shift = BIT(byte , 0);
+ pixels_e = pixels_o = uint16_t(byte & 0xfe);
+ if (half_shift) {
+ pixels_e <<= 1;
+ if (BIT(pixels_o , 7)) {
+ BIT_SET(pixels_o, 8);
}
}
}
if (iv) {
- pixels = ~pixels;
+ pixels_e = ~pixels_e;
+ pixels_o = ~pixels_o;
}
unsigned on_pen = BIT(attrs , 3) ? 1 : 2;
- for (unsigned x = 0; x < VIDEO_CHAR_WIDTH * 2; x++) {
- m_bitmap.pix32(video_scanline , x_left + x) = m_palette->pen(BIT(pixels , 0) ? on_pen : 0);
- pixels >>= 1;
+ for (unsigned x = 0; x < VIDEO_CHAR_WIDTH * 2; x += 2) {
+ m_bitmap.pix32(video_scanline , x_left + x) = m_palette->pen(BIT(pixels_e , 0) ? on_pen : 0);
+ m_bitmap.pix32(video_scanline , x_left + x + 1) = m_palette->pen(BIT(pixels_o , 0) ? on_pen : 0);
+ pixels_e >>= 1;
+ pixels_o >>= 1;
}
}
}
+static const unsigned baud_rate_divisors[] = {
+ 0, // 0: external clock (here: no clock)
+ 2800, // 1: 110 baud
+ 2048, // 2: 150 baud
+ 1024, // 3: 300 baud
+ 256, // 4: 1200 baud
+ 128, // 5: 2400 baud
+ 64, // 6: 4800 baud
+ 32 // 7: 9600 baud
+};
+
+void hp2645_state::update_async_control(uint8_t new_control)
+{
+ LOG("ASYNC CT=%02x\n" , new_control);
+ uint8_t diff = m_async_control ^ new_control;
+ m_async_control = new_control;
+ m_rs232->write_rts(BIT(m_async_control , 0));
+ if (diff & 0x0e) {
+ unsigned new_rate_idx = (m_async_control >> 1) & 0x07;
+ // Set baud rate
+ double rxc_txc_freq;
+ if (new_rate_idx == 0) {
+ rxc_txc_freq = 0.0;
+ } else {
+ rxc_txc_freq = double(SYS_CLOCK) / baud_rate_divisors[ new_rate_idx ];
+ }
+ m_uart->set_receiver_clock(rxc_txc_freq);
+ m_uart->set_transmitter_clock(rxc_txc_freq);
+ m_uart->set_input_pin(AY31015_TSB , new_rate_idx == 1);
+ LOG("ASYNC freq=%f\n" , rxc_txc_freq);
+ }
+ if (diff & 0x30) {
+ m_uart->set_input_pin(AY31015_NP , BIT(new_control , 5));
+ m_uart->set_input_pin(AY31015_NB1 , BIT(new_control , 5));
+ m_uart->set_input_pin(AY31015_EPS , BIT(new_control , 4));
+ }
+ // Update TxD
+ async_txd_w(0);
+}
+
+void hp2645_state::update_async_irq()
+{
+ m_datacom_irq = m_uart->get_output_pin(AY31015_DAV);
+ LOG("ASYNC IRQ=%d\n" , m_datacom_irq);
+ update_irq();
+}
+
#define IOP_MASK(x) BIT_MASK<ioport_value>((x))
static INPUT_PORTS_START(hp2645)
@@ -523,7 +750,7 @@ static INPUT_PORTS_START(hp2645)
PORT_BIT(IOP_MASK(21) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_3_PAD) PORT_CHAR(UCHAR_MAMEKEY(3_PAD)) // 025 PAD3
PORT_BIT(IOP_MASK(22) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_6_PAD) PORT_CHAR(UCHAR_MAMEKEY(6_PAD)) // 026 PAD6
PORT_BIT(IOP_MASK(23) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5)) PORT_NAME("f5") // 027 F5
- PORT_BIT(IOP_MASK(24) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("Memory lock") // 030 MEMORY LOCK
+ PORT_BIT(IOP_MASK(24) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_TOGGLE PORT_NAME("Memory lock") // 030 MEMORY LOCK
PORT_BIT(IOP_MASK(25) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#') // 031 3
PORT_BIT(IOP_MASK(26) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E') // 032 E
PORT_BIT(IOP_MASK(27) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C') // 033 C
@@ -614,11 +841,112 @@ static INPUT_PORTS_START(hp2645)
PORT_BIT(IOP_MASK(13) , IP_ACTIVE_HIGH , IPT_UNUSED) // 155
PORT_BIT(IOP_MASK(14) , IP_ACTIVE_HIGH , IPT_UNUSED) // 156
PORT_BIT(IOP_MASK(15) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1)) PORT_NAME("f1") // 157 F1
+
+ // Default: Full duplex, no parity, 9600 bps
+ PORT_START("comm")
+ PORT_CONFNAME(0x80, 0x80, "Duplex")
+ PORT_CONFSETTING(0x80, "Full")
+ PORT_CONFSETTING(0x00, "Half")
+ PORT_CONFNAME(0x30, 0x20, "Parity")
+ PORT_CONFSETTING(0x00, "Odd")
+ PORT_CONFSETTING(0x10, "Even")
+ PORT_CONFSETTING(0x20, "None")
+ PORT_CONFNAME(0x0e, 0x0e, "Baud rate")
+ PORT_CONFSETTING(0x00, "Ext")
+ PORT_CONFSETTING(0x02, "110")
+ PORT_CONFSETTING(0x04, "150")
+ PORT_CONFSETTING(0x06, "300")
+ PORT_CONFSETTING(0x08, "1200")
+ PORT_CONFSETTING(0x0a, "2400")
+ PORT_CONFSETTING(0x0c, "4800")
+ PORT_CONFSETTING(0x0e, "9600")
+
+ // Default: all switches closed except R, U & V
+ // This setting should work for standard character-oriented I/O
+ PORT_START("sw_ah")
+ PORT_CONFNAME(0x01, 0x00, "Switch A")
+ PORT_CONFSETTING(0x00, DEF_STR(On))
+ PORT_CONFSETTING(0x01, DEF_STR(Off))
+ PORT_CONFNAME(0x02, 0x00, "Switch B")
+ PORT_CONFSETTING(0x00, DEF_STR(On))
+ PORT_CONFSETTING(0x02, DEF_STR(Off))
+ PORT_CONFNAME(0x04, 0x00, "Switch C")
+ PORT_CONFSETTING(0x00, DEF_STR(On))
+ PORT_CONFSETTING(0x04, DEF_STR(Off))
+ PORT_CONFNAME(0x08, 0x00, "Switch D")
+ PORT_CONFSETTING(0x00, DEF_STR(On))
+ PORT_CONFSETTING(0x08, DEF_STR(Off))
+ PORT_CONFNAME(0x10, 0x00, "Switch E")
+ PORT_CONFSETTING(0x00, DEF_STR(On))
+ PORT_CONFSETTING(0x10, DEF_STR(Off))
+ PORT_CONFNAME(0x20, 0x00, "Switch F")
+ PORT_CONFSETTING(0x00, DEF_STR(On))
+ PORT_CONFSETTING(0x20, DEF_STR(Off))
+ PORT_CONFNAME(0x40, 0x00, "Switch G")
+ PORT_CONFSETTING(0x00, DEF_STR(On))
+ PORT_CONFSETTING(0x40, DEF_STR(Off))
+ PORT_CONFNAME(0x80, 0x00, "Switch H")
+ PORT_CONFSETTING(0x00, DEF_STR(On))
+ PORT_CONFSETTING(0x80, DEF_STR(Off))
+ PORT_START("sw_jr")
+ PORT_CONFNAME(0x01, 0x00, "Switch J")
+ PORT_CONFSETTING(0x00, DEF_STR(On))
+ PORT_CONFSETTING(0x01, DEF_STR(Off))
+ PORT_CONFNAME(0x02, 0x00, "Switch K")
+ PORT_CONFSETTING(0x00, DEF_STR(On))
+ PORT_CONFSETTING(0x02, DEF_STR(Off))
+ PORT_CONFNAME(0x04, 0x00, "Switch L")
+ PORT_CONFSETTING(0x00, DEF_STR(On))
+ PORT_CONFSETTING(0x04, DEF_STR(Off))
+ PORT_CONFNAME(0x08, 0x00, "Switch M")
+ PORT_CONFSETTING(0x00, DEF_STR(On))
+ PORT_CONFSETTING(0x08, DEF_STR(Off))
+ PORT_CONFNAME(0x10, 0x00, "Switch N")
+ PORT_CONFSETTING(0x00, DEF_STR(On))
+ PORT_CONFSETTING(0x10, DEF_STR(Off))
+ PORT_CONFNAME(0x20, 0x00, "Switch P")
+ PORT_CONFSETTING(0x00, DEF_STR(On))
+ PORT_CONFSETTING(0x20, DEF_STR(Off))
+ PORT_CONFNAME(0x40, 0x00, "Switch Q")
+ PORT_CONFSETTING(0x00, DEF_STR(On))
+ PORT_CONFSETTING(0x40, DEF_STR(Off))
+ PORT_CONFNAME(0x80, 0x80, "Switch R")
+ PORT_CONFSETTING(0x00, DEF_STR(On))
+ PORT_CONFSETTING(0x80, DEF_STR(Off))
+ PORT_START("sw_sz")
+ PORT_CONFNAME(0x01, 0x00, "Switch S")
+ PORT_CONFSETTING(0x00, DEF_STR(On))
+ PORT_CONFSETTING(0x01, DEF_STR(Off))
+ PORT_CONFNAME(0x02, 0x00, "Switch T")
+ PORT_CONFSETTING(0x00, DEF_STR(On))
+ PORT_CONFSETTING(0x02, DEF_STR(Off))
+ PORT_CONFNAME(0x04, 0x04, "Switch U")
+ PORT_CONFSETTING(0x00, DEF_STR(On))
+ PORT_CONFSETTING(0x04, DEF_STR(Off))
+ PORT_CONFNAME(0x08, 0x08, "Switch V")
+ PORT_CONFSETTING(0x00, DEF_STR(On))
+ PORT_CONFSETTING(0x08, DEF_STR(Off))
+ PORT_CONFNAME(0x10, 0x00, "Switch W")
+ PORT_CONFSETTING(0x00, DEF_STR(On))
+ PORT_CONFSETTING(0x10, DEF_STR(Off))
+ PORT_CONFNAME(0x20, 0x00, "Switch X")
+ PORT_CONFSETTING(0x00, DEF_STR(On))
+ PORT_CONFSETTING(0x20, DEF_STR(Off))
+ PORT_CONFNAME(0x40, 0x00, "Switch Y")
+ PORT_CONFSETTING(0x00, DEF_STR(On))
+ PORT_CONFSETTING(0x40, DEF_STR(Off))
+ PORT_CONFNAME(0x80, 0x00, "Switch Z")
+ PORT_CONFSETTING(0x00, DEF_STR(On))
+ PORT_CONFSETTING(0x80, DEF_STR(Off))
INPUT_PORTS_END
static ADDRESS_MAP_START(cpu_mem_map , AS_PROGRAM , 8 , hp2645_state)
ADDRESS_MAP_UNMAP_LOW
AM_RANGE(0x0000 , 0x57ff) AM_ROM
+ AM_RANGE(0x8100 , 0x8100) AM_READ(async_data_r)
+ AM_RANGE(0x8120 , 0x8120) AM_READ(async_status_r)
+ AM_RANGE(0x8140 , 0x8140) AM_WRITE(async_control_w)
+ AM_RANGE(0x8160 , 0x8160) AM_WRITE(async_data_w)
AM_RANGE(0x8300 , 0x8300) AM_WRITE(kb_led_w)
AM_RANGE(0x8300 , 0x830d) AM_READ(kb_r)
AM_RANGE(0x830e , 0x830e) AM_READ(switches_ah_r)
@@ -657,6 +985,22 @@ static MACHINE_CONFIG_START(hp2645)
MCFG_TIMER_DRIVER_ADD_SCANLINE("scantimer", hp2645_state, scanline_timer, "screen", 0, 1)
MCFG_PALETTE_ADD_MONOCHROME_HIGHLIGHT("palette")
MCFG_DEFAULT_LAYOUT(layout_hp2640)
+
+ // RS232
+ MCFG_RS232_PORT_ADD("rs232" , default_rs232_devices , nullptr)
+
+ // UART
+ MCFG_DEVICE_ADD("uart", AY31015, 0)
+ MCFG_AY31015_READ_SI_CB(DEVREADLINE("rs232" , rs232_port_device , rxd_r))
+ MCFG_AY31015_WRITE_SO_CB(WRITELINE(hp2645_state , async_txd_w))
+ MCFG_AY31015_STATUS_CHANGED_CB(WRITE8(hp2645_state , async_status_change))
+
+ // Beep
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+ MCFG_SOUND_ADD("beep" , BEEP , BEEP_FREQUENCY)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS , "mono" , 1.00)
+ MCFG_TIMER_DRIVER_ADD("timer_beep" , hp2645_state , timer_beep_exp)
+
MACHINE_CONFIG_END
ROM_START(hp2645)
@@ -676,6 +1020,15 @@ ROM_START(hp2645)
ROM_REGION(0x2000, "chargen0", 0)
ROM_LOAD("1816-0612.bin", 0x0000, 0x400, CRC(5d7befd6) SHA1(31357e7b8630f52698f1b6825e79c7a51ff3f245))
ROM_LOAD("1816-0613.bin", 0x0400, 0x400, CRC(b6bac431) SHA1(42a557ecff769425d295ebbd1b73b26ddbfd3a09))
+
+ ROM_REGION(0x1000, "chargen1", 0)
+ ROM_LOAD("1816-0642.bin", 0x0000, 0x400, CRC(2b8d151d) SHA1(208ae3ec780eb8bbbe6ac39cc61141730eda7fdd))
+
+ ROM_REGION(0x1000, "chargen2", 0)
+ ROM_LOAD("1816-1417.bin", 0x0000, 0x400, CRC(e91343a4) SHA1(b37be2f3699bc8766435b5ee3775d36510df8d1e))
+
+ ROM_REGION(0x1000, "chargen3", 0)
+ ROM_LOAD("1816-1425.bin", 0x0000, 0x400, CRC(69a34fef) SHA1(816929cadd53c2fe42b3ca561c029cb1ccd4ca24))
ROM_END
-COMP(1976 , hp2645 , 0 , 0 , hp2645 , hp2645 , hp2645_state , 0 , "HP" , "HP 2645A" , MACHINE_NO_SOUND)
+COMP(1976 , hp2645 , 0 , 0 , hp2645 , hp2645 , hp2645_state , 0 , "HP" , "HP 2645A" , 0)