// license:BSD-3-Clause
// copyright-holders:F. Ulivi
// **************************
// Driver for HP 9825 systems
// **************************
//
// **** Temporary header, will hopefully evolve into proper doc ****
//
// What's in:
// - Emulation of 9825B system
// - 12 kw of RAMs
// - 12 kw of system ROM
// - Keyboard (SHIFT LOCK & RESET not implemented)
// - Display & run light
// - DC100 tape drive
// - Printer
// - Beeper
// - Internal expansion ROMs
// What's not yet in:
// - External expansion ROMs
// - Configurable RAM size
// - I/O expansion slots: 98034 & 98035 modules from hp9845 emulation can be used here, too
//
// 9825A & 9825T can also be emulated. At the moment I haven't all the necessary
// ROM dumps, though.
#include "emu.h"
#include "cpu/hphybrid/hphybrid.h"
#include "machine/timer.h"
#include "machine/hp9825_tape.h"
#include "machine/hp98x5_io_sys.h"
#include "bus/hp9845_io/hp9845_io.h"
#include "imagedev/bitbngr.h"
#include "speaker.h"
#include "sound/beep.h"
#include "hp9825.lh"
// CPU clock (generated by a trimmered RC oscillator)
constexpr unsigned MAIN_CLOCK = 6000000;
// KDP chip clock
constexpr unsigned KDP_CLOCK = MAIN_CLOCK / 4;
// Peripheral Addresses (PA)
constexpr uint8_t KDP_PA = 0;
constexpr uint8_t TAPE_PA = 1;
constexpr uint8_t IO_SLOT_FIRST_PA = 2;
constexpr uint8_t IO_SLOT_LAST_PA = 15;
// KDP clocks to print 1 line of dots (~33 ms)
// This value is semi-guessed.
constexpr unsigned KDP_CLOCKS_PER_LINE = 50000;
// Beeper constants
// Values come from R/C values on schematics
constexpr unsigned BEEPER_FREQ = 900;
constexpr unsigned BEEPER_MS = 40;
// Bit manipulation
namespace {
template<typename T> constexpr T BIT_MASK(unsigned n)
{
return (T)1U << n;
}
template<typename T> void BIT_CLR(T& w , unsigned n)
{
w &= ~BIT_MASK<T>(n);
}
template<typename T> void BIT_SET(T& w , unsigned n)
{
w |= BIT_MASK<T>(n);
}
}
class hp9825_state : public driver_device
{
public:
hp9825_state(const machine_config &mconfig, device_type type, const char *tag)
: driver_device(mconfig, type, tag)
, m_cpu(*this , "cpu")
, m_io_sys(*this , "io_sys")
, m_cursor_timer(*this , "cursor_timer")
, m_tape(*this , "tape")
, m_io_key(*this , "KEY%u" , 0)
, m_shift_key(*this , "KEY_SHIFT")
, m_prt_alpha_out(*this , "prt_alpha")
, m_prt_graph_out(*this , "prt_graph")
, m_prt_timer(*this , "prt_timer")
, m_beeper(*this , "beeper")
, m_beep_timer(*this , "beep_timer")
, m_io_slot(*this, "slot%u", 0U)
, m_display(*this , "char_%u_%u" , 0U , 0U)
, m_run_light(*this , "run_light")
{
}
void hp9825b(machine_config &config);
protected:
virtual void machine_start() override;
virtual void device_reset() override;
virtual void machine_reset() override;
private:
required_device<hp_09825_67907_cpu_device> m_cpu;
required_device<hp98x5_io_sys_device> m_io_sys;
required_device<timer_device> m_cursor_timer;
required_device<hp9825_tape_device> m_tape;
required_ioport_array<4> m_io_key;
required_ioport m_shift_key;
required_device<bitbanger_device> m_prt_alpha_out;
required_device<bitbanger_device> m_prt_graph_out;
required_device<timer_device> m_prt_timer;
required_device<beep_device> m_beeper;
required_device<timer_device> m_beep_timer;
required_device_array<hp9845_io_slot_device , 3> m_io_slot;
output_finder<32 , 7> m_display;
output_finder<> m_run_light;
bool m_display_on;
uint8_t m_display_mem[ 32 ];
uint8_t m_display_idx;
bool m_rpl_cursor;
bool m_cursor_blink;
bool m_any_cursor;
uint8_t m_scancode;
bool m_key_pressed;
bool m_autorepeating;
unsigned m_autorepeat_cnt;
// Printer
uint8_t m_printer_mem[ 16 ];
uint8_t m_printer_idx;
unsigned m_printer_line; // 0: printer idle, 1..10: line being printed
// SC of slots
int m_slot_sc[ 3 ];
void cpu_io_map(address_map &map);
void cpu_mem_map(address_map &map);
DECLARE_READ16_MEMBER(kb_scancode_r);
DECLARE_WRITE16_MEMBER(disp_w);
DECLARE_READ16_MEMBER(kdp_status_r);
DECLARE_WRITE16_MEMBER(kdp_control_w);
DECLARE_WRITE16_MEMBER(printer_w);
void update_display();
TIMER_DEVICE_CALLBACK_MEMBER(cursor_blink);
void kb_scan_ioport(ioport_value pressed , ioport_port &port , unsigned idx_base , int& max_seq_len , unsigned& max_seq_idx);
TIMER_DEVICE_CALLBACK_MEMBER(kb_scan);
TIMER_DEVICE_CALLBACK_MEMBER(prt_timer);
TIMER_DEVICE_CALLBACK_MEMBER(beep_timer);
// Slot handling
void set_irq_slot(unsigned slot , int state);
void set_sts_slot(unsigned slot , int state);
void set_flg_slot(unsigned slot , int state);
void set_dmar_slot(unsigned slot , int state);
};
void hp9825_state::machine_start()
{
m_display.resolve();
m_run_light.resolve();
save_item(NAME(m_display_on));
save_item(NAME(m_display_mem));
save_item(NAME(m_display_idx));
save_item(NAME(m_scancode));
}
void hp9825_state::device_reset()
{
// First, unmap every r/w handler in 1..12 select codes
for (unsigned sc = IO_SLOT_FIRST_PA; sc < (IO_SLOT_LAST_PA + 1); sc++) {
m_cpu->space(AS_IO).unmap_readwrite(sc * 4 , sc * 4 + 3);
}
// Then, set r/w handlers of all installed I/O cards
int sc;
read16_delegate rhandler;
write16_delegate whandler;
for (unsigned i = 0; i < 3; i++) {
if ((sc = m_io_slot[ i ]->get_rw_handlers(rhandler , whandler)) >= 0) {
logerror("Install R/W handlers for slot %u @ SC = %d\n", i, sc);
m_cpu->space(AS_IO).install_readwrite_handler(sc * 4 , sc * 4 + 3 , rhandler , whandler);
}
m_slot_sc[ i ] = sc;
}
}
void hp9825_state::machine_reset()
{
m_display_on = false;
m_display_idx = 0;
m_rpl_cursor = false;
m_cursor_timer->reset();
m_cursor_blink = true;
update_display();
m_scancode = 0;
m_key_pressed = false;
m_autorepeating = false;
m_autorepeat_cnt = 0;
m_printer_idx = 0;
m_printer_line = 0;
m_prt_timer->reset();
m_beeper->set_state(0);
m_beep_timer->reset();
}
void hp9825_state::cpu_io_map(address_map &map)
{
map.unmap_value_low();
map(HP_MAKE_IOADDR(KDP_PA , 0) , HP_MAKE_IOADDR(KDP_PA , 0)).rw(FUNC(hp9825_state::kb_scancode_r) , FUNC(hp9825_state::disp_w));
map(HP_MAKE_IOADDR(KDP_PA , 1) , HP_MAKE_IOADDR(KDP_PA , 1)).rw(FUNC(hp9825_state::kdp_status_r) , FUNC(hp9825_state::kdp_control_w));
map(HP_MAKE_IOADDR(KDP_PA , 2) , HP_MAKE_IOADDR(KDP_PA , 2)).w(FUNC(hp9825_state::printer_w));
map(HP_MAKE_IOADDR(TAPE_PA , 0) , HP_MAKE_IOADDR(TAPE_PA , 3)).rw(m_tape , FUNC(hp9825_tape_device::tape_r) , FUNC(hp9825_tape_device::tape_w));
// TODO:
}
void hp9825_state::cpu_mem_map(address_map &map)
{
map.unmap_value_low();
map(0x0000 , 0x2fff).rom();
map(0x3400 , 0x3bff).rom();
map(0x4000 , 0x4fff).rom();
map(0x5000 , 0x7fff).ram();
}
READ16_MEMBER(hp9825_state::kb_scancode_r)
{
uint8_t res = m_scancode;
if (m_shift_key->read()) {
BIT_SET(res , 7);
}
m_io_sys->set_irq(KDP_PA , false);
return res;
}
WRITE16_MEMBER(hp9825_state::disp_w)
{
if (m_display_on) {
m_display_on = false;
m_cursor_timer->reset();
m_cursor_blink = true;
m_display_idx = 0;
update_display();
}
m_display_mem[ m_display_idx++ ] = uint8_t(data);
}
READ16_MEMBER(hp9825_state::kdp_status_r)
{
uint16_t res = 8;
if (m_io_sys->is_irq_pending(KDP_PA)) {
BIT_SET(res , 4);
}
if (m_printer_line) {
BIT_SET(res , 2);
}
return res;
}
WRITE16_MEMBER(hp9825_state::kdp_control_w)
{
bool regen_display = false;
if (BIT(data , 1) && !m_display_on) {
m_display_on = true;
// Cursor should blink at 2^-19 the KDP clock
attotime cursor_half_period{ attotime::from_ticks(262144 , KDP_CLOCK) };
m_cursor_timer->adjust(cursor_half_period , 0 , cursor_half_period);
regen_display = true;
}
if (BIT(data , 6) && !m_rpl_cursor) {
m_rpl_cursor = true;
regen_display = true;
}
if (BIT(data , 5) && m_rpl_cursor) {
m_rpl_cursor = false;
regen_display = true;
}
if (BIT(data , 4)) {
if (BIT(data , 3)) {
m_run_light = !m_run_light;
} else {
m_run_light = false;
}
} else if (BIT(data , 3)) {
m_run_light = true;
}
if (BIT(data , 0) && m_printer_line == 0) {
// Start printing
// Dump text line to alpha bitbanger
for (auto c : m_printer_mem) {
m_prt_alpha_out->output(c);
}
m_prt_alpha_out->output('\n');
m_printer_idx = 0;
m_printer_line++;
m_prt_timer->adjust(attotime::from_ticks(KDP_CLOCKS_PER_LINE , KDP_CLOCK));
}
if (BIT(data , 2)) {
// Start beeper
m_beeper->set_state(1);
m_beep_timer->adjust(attotime::from_msec(BEEPER_MS));
}
if (regen_display) {
update_display();
}
}
WRITE16_MEMBER(hp9825_state::printer_w)
{
m_printer_mem[ m_printer_idx ] = uint8_t(data);
m_printer_idx = (m_printer_idx + 1) & 0xf;
}
// The character generator was reverse engineered from images of printer & display test patterns.
// It is not guaranteed to be pixel-accurate though it looks quite close to the original.
static const uint8_t chargen[ 128 ][ 5 ] = {
{ 0x08,0x1c,0x3e,0x7f,0x00 }, // 00
{ 0x30,0x48,0x45,0x40,0x30 }, // 01
{ 0x45,0x29,0x11,0x29,0x45 }, // 02
{ 0x7d,0x09,0x11,0x21,0x7d }, // 03
{ 0x38,0x44,0x44,0x38,0x44 }, // 04
{ 0x7c,0x2a,0x4a,0x4a,0x34 }, // 05
{ 0x7f,0x01,0x01,0x01,0x03 }, // 06
{ 0x7d,0x09,0x05,0x05,0x79 }, // 07
{ 0x60,0x58,0x46,0x58,0x60 }, // 08
{ 0x38,0x44,0x44,0x3c,0x04 }, // 09
{ 0x10,0x20,0x7f,0x20,0x10 }, // 0a
{ 0x62,0x14,0x08,0x10,0x60 }, // 0b
{ 0x40,0x3c,0x20,0x20,0x1c }, // 0c
{ 0x08,0x1c,0x2a,0x08,0x08 }, // 0d
{ 0x10,0x08,0x78,0x08,0x04 }, // 0e
{ 0x08,0x55,0x7f,0x55,0x08 }, // 0f
{ 0x3e,0x49,0x49,0x49,0x3e }, // 10
{ 0x5e,0x61,0x01,0x61,0x5e }, // 11
{ 0x30,0x4a,0x4d,0x49,0x30 }, // 12
{ 0x78,0x14,0x15,0x14,0x78 }, // 13
{ 0x38,0x44,0x45,0x3c,0x40 }, // 14
{ 0x78,0x15,0x14,0x15,0x78 }, // 15
{ 0x38,0x45,0x44,0x3d,0x40 }, // 16
{ 0x3c,0x43,0x42,0x43,0x3c }, // 17
{ 0x38,0x45,0x44,0x45,0x38 }, // 18
{ 0x3e,0x41,0x40,0x41,0x3e }, // 19
{ 0x3c,0x41,0x40,0x41,0x3c }, // 1a
{ 0x7e,0x09,0x7f,0x49,0x49 }, // 1b
{ 0x38,0x44,0x38,0x54,0x58 }, // 1c
{ 0x12,0x19,0x15,0x12,0x00 }, // 1d
{ 0x48,0x7e,0x49,0x41,0x42 }, // 1e
{ 0x55,0x2a,0x55,0x2a,0x55 }, // 1f
{ 0x00,0x00,0x00,0x00,0x00 }, // 20
{ 0x00,0x5f,0x00,0x00,0x00 }, // 21
{ 0x00,0x03,0x00,0x03,0x00 }, // 22
{ 0x14,0x7f,0x14,0x7f,0x14 }, // 23
{ 0x24,0x2a,0x7f,0x2a,0x12 }, // 24
{ 0x23,0x13,0x08,0x64,0x62 }, // 25
{ 0x36,0x49,0x56,0x20,0x50 }, // 26
{ 0x00,0x0b,0x07,0x00,0x00 }, // 27
{ 0x00,0x00,0x3e,0x41,0x00 }, // 28
{ 0x00,0x41,0x3e,0x00,0x00 }, // 29
{ 0x08,0x2a,0x1c,0x2a,0x08 }, // 2a
{ 0x08,0x08,0x3e,0x08,0x08 }, // 2b
{ 0x00,0x58,0x38,0x00,0x00 }, // 2c
{ 0x08,0x08,0x08,0x08,0x08 }, // 2d
{ 0x00,0x60,0x60,0x00,0x00 }, // 2e
{ 0x20,0x10,0x08,0x04,0x02 }, // 2f
{ 0x3e,0x51,0x49,0x45,0x3e }, // 30
{ 0x00,0x42,0x7f,0x40,0x00 }, // 31
{ 0x62,0x51,0x49,0x49,0x46 }, // 32
{ 0x22,0x41,0x49,0x49,0x36 }, // 33
{ 0x18,0x14,0x12,0x7f,0x10 }, // 34
{ 0x27,0x45,0x45,0x45,0x39 }, // 35
{ 0x3c,0x4a,0x49,0x49,0x30 }, // 36
{ 0x01,0x71,0x09,0x05,0x03 }, // 37
{ 0x36,0x49,0x49,0x49,0x36 }, // 38
{ 0x06,0x49,0x49,0x29,0x1e }, // 39
{ 0x00,0x36,0x36,0x00,0x00 }, // 3a
{ 0x00,0x5b,0x3b,0x00,0x00 }, // 3b
{ 0x00,0x08,0x14,0x22,0x41 }, // 3c
{ 0x14,0x14,0x14,0x14,0x14 }, // 3d
{ 0x41,0x22,0x14,0x08,0x00 }, // 3e
{ 0x06,0x01,0x51,0x09,0x06 }, // 3f
{ 0x3e,0x41,0x5d,0x55,0x1e }, // 40
{ 0x7e,0x09,0x09,0x09,0x7e }, // 41
{ 0x7f,0x49,0x49,0x49,0x36 }, // 42
{ 0x3e,0x41,0x41,0x41,0x22 }, // 43
{ 0x7f,0x41,0x41,0x41,0x3e }, // 44
{ 0x7f,0x49,0x49,0x49,0x41 }, // 45
{ 0x7f,0x09,0x09,0x09,0x01 }, // 46
{ 0x3e,0x41,0x41,0x51,0x72 }, // 47
{ 0x7f,0x08,0x08,0x08,0x7f }, // 48
{ 0x00,0x41,0x7f,0x41,0x00 }, // 49
{ 0x20,0x40,0x40,0x40,0x3f }, // 4a
{ 0x7f,0x08,0x14,0x22,0x41 }, // 4b
{ 0x7f,0x40,0x40,0x40,0x40 }, // 4c
{ 0x7f,0x02,0x0c,0x02,0x7f }, // 4d
{ 0x7f,0x04,0x08,0x10,0x7f }, // 4e
{ 0x3e,0x41,0x41,0x41,0x3e }, // 4f
{ 0x7f,0x09,0x09,0x09,0x06 }, // 50
{ 0x3e,0x41,0x51,0x21,0x5e }, // 51
{ 0x7f,0x09,0x19,0x29,0x46 }, // 52
{ 0x26,0x49,0x49,0x49,0x32 }, // 53
{ 0x01,0x01,0x7f,0x01,0x01 }, // 54
{ 0x3f,0x40,0x40,0x40,0x3f }, // 55
{ 0x07,0x18,0x60,0x18,0x07 }, // 56
{ 0x7f,0x20,0x10,0x20,0x7f }, // 57
{ 0x63,0x14,0x08,0x14,0x63 }, // 58
{ 0x03,0x04,0x78,0x04,0x03 }, // 59
{ 0x61,0x51,0x49,0x45,0x43 }, // 5a
{ 0x00,0x00,0x7f,0x41,0x41 }, // 5b
{ 0x20,0x7f,0x01,0x01,0x01 }, // 5c
{ 0x41,0x41,0x7f,0x00,0x00 }, // 5d
{ 0x04,0x02,0x7f,0x02,0x04 }, // 5e
{ 0x40,0x40,0x40,0x40,0x40 }, // 5f
{ 0x00,0x07,0x0b,0x00,0x00 }, // 60
{ 0x38,0x44,0x44,0x3c,0x40 }, // 61
{ 0x7f,0x48,0x44,0x44,0x38 }, // 62
{ 0x38,0x44,0x44,0x44,0x20 }, // 63
{ 0x38,0x44,0x44,0x48,0x7f }, // 64
{ 0x38,0x54,0x54,0x54,0x08 }, // 65
{ 0x08,0x7e,0x09,0x02,0x00 }, // 66
{ 0x08,0x14,0x54,0x54,0x3c }, // 67
{ 0x7f,0x08,0x04,0x04,0x78 }, // 68
{ 0x00,0x44,0x7d,0x40,0x00 }, // 69
{ 0x20,0x40,0x44,0x3d,0x00 }, // 6a
{ 0x7f,0x10,0x28,0x44,0x00 }, // 6b
{ 0x00,0x41,0x7f,0x40,0x00 }, // 6c
{ 0x78,0x04,0x18,0x04,0x78 }, // 6d
{ 0x7c,0x08,0x04,0x04,0x78 }, // 6e
{ 0x38,0x44,0x44,0x44,0x38 }, // 6f
{ 0x7c,0x14,0x24,0x24,0x18 }, // 70
{ 0x18,0x24,0x14,0x7c,0x40 }, // 71
{ 0x7c,0x08,0x04,0x04,0x00 }, // 72
{ 0x48,0x54,0x54,0x54,0x20 }, // 73
{ 0x04,0x3e,0x44,0x20,0x00 }, // 74
{ 0x3c,0x40,0x40,0x20,0x7c }, // 75
{ 0x1c,0x20,0x40,0x20,0x1c }, // 76
{ 0x3c,0x40,0x30,0x40,0x3c }, // 77
{ 0x44,0x28,0x10,0x28,0x44 }, // 78
{ 0x04,0x48,0x30,0x08,0x04 }, // 79
{ 0x44,0x64,0x54,0x4c,0x44 }, // 7a
{ 0x08,0x7c,0x04,0x7c,0x02 }, // 7b
{ 0x00,0x00,0x7f,0x00,0x00 }, // 7c
{ 0x08,0x08,0x2a,0x1c,0x08 }, // 7d
{ 0x41,0x63,0x55,0x49,0x63 }, // 7e
{ 0x7f,0x08,0x08,0x08,0x08 } // 7f
};
void hp9825_state::update_display()
{
m_any_cursor = false;
for (unsigned i = 0; i < 32; ++i) {
bool cursor_here = BIT(m_display_mem[ i ] , 7);
if (cursor_here) {
m_any_cursor = true;
}
bool show_cursor = m_cursor_blink && cursor_here;
uint8_t char_code = m_display_mem[ i ] & 0x7f;
for (unsigned j = 0; j < 7; ++j) {
uint8_t five_dots = 0;
if (m_display_on) {
for (unsigned col = 0; col < 5; col++) {
uint8_t char_col;
if (show_cursor) {
if (m_rpl_cursor) {
// Replace cursor: all pixels lit
char_col = ~0;
} else {
// Insert cursor: character code 0
char_col = chargen[ 0 ][ col ];
}
} else {
char_col = chargen[ char_code ][ col ];
}
if (BIT(char_col , j)) {
BIT_SET(five_dots , col);
}
}
}
m_display[ i ][ j ] = five_dots;
}
}
}
TIMER_DEVICE_CALLBACK_MEMBER(hp9825_state::cursor_blink)
{
m_cursor_blink = !m_cursor_blink;
if (m_any_cursor) {
update_display();
}
}
TIMER_DEVICE_CALLBACK_MEMBER(hp9825_state::kb_scan)
{
ioport_value input[ 4 ]
{ m_io_key[ 0 ]->read(),
m_io_key[ 1 ]->read(),
m_io_key[ 2 ]->read(),
m_io_key[ 3 ]->read()
};
if (m_key_pressed) {
// Still pressed ?
m_key_pressed = BIT(input[ m_scancode / 32 ] , m_scancode % 32);
} else {
int max_seq_len = 0;
unsigned max_seq_idx = 0;
for (unsigned i = 0; i < 4; i++) {
kb_scan_ioport(input[ i ] , *m_io_key[ i ] , i << 5 , max_seq_len , max_seq_idx);
}
if (max_seq_len) {
m_scancode = max_seq_idx;
m_key_pressed = true;
m_io_sys->set_irq(KDP_PA , true);
}
}
if (m_key_pressed) {
auto prev_cnt = m_autorepeat_cnt;
m_autorepeat_cnt++;
// Auto-repeat initial delay & frequency are entirely guessed..
if (BIT(m_autorepeat_cnt , 5)) {
// Initial delay passed
m_autorepeating = true;
}
if (m_autorepeating && BIT(~prev_cnt & m_autorepeat_cnt , 3)) {
// Repeat key every time bit 3 of autorepeat counter goes 0->1
m_io_sys->set_irq(KDP_PA , true);
}
} else {
m_autorepeating = false;
m_autorepeat_cnt = 0;
}
}
void hp9825_state::kb_scan_ioport(ioport_value pressed , ioport_port &port , unsigned idx_base , int& max_seq_len , unsigned& max_seq_idx)
{
while (pressed) {
unsigned bit_no = 31 - count_leading_zeros(pressed);
ioport_value mask = BIT_MASK<ioport_value>(bit_no);
int seq_len = port.field(mask)->seq().length();
if (seq_len > max_seq_len) {
max_seq_len = seq_len;
max_seq_idx = bit_no + idx_base;
}
pressed &= ~mask;
}
}
TIMER_DEVICE_CALLBACK_MEMBER(hp9825_state::prt_timer)
{
if (m_printer_line == 1 || m_printer_line == 9 || m_printer_line == 10) {
// Empty lines
for (unsigned i = 0; i < 110; i++) {
m_prt_graph_out->output(' ');
}
} else {
for (unsigned i = 0; i < 16; i++) {
for (unsigned col = 0; col < 5; col++) {
uint8_t pixels = chargen[ m_printer_mem[ i ] & 0x7f ][ col ];
m_prt_graph_out->output(BIT(pixels , m_printer_line - 2) ? '*' : ' ');
}
m_prt_graph_out->output(' ');
m_prt_graph_out->output(' ');
}
}
m_prt_graph_out->output('\n');
m_printer_line++;
if (m_printer_line <= 10) {
m_prt_timer->adjust(attotime::from_ticks(KDP_CLOCKS_PER_LINE , KDP_CLOCK));
} else {
m_printer_line = 0;
}
}
TIMER_DEVICE_CALLBACK_MEMBER(hp9825_state::beep_timer)
{
m_beeper->set_state(0);
}
void hp9825_state::set_irq_slot(unsigned slot , int state)
{
int sc = m_slot_sc[ slot ];
assert(sc >= 0);
m_io_sys->set_irq(uint8_t(sc) , state);
}
void hp9825_state::set_sts_slot(unsigned slot , int state)
{
int sc = m_slot_sc[ slot ];
assert(sc >= 0);
m_io_sys->set_sts(uint8_t(sc) , state);
}
void hp9825_state::set_flg_slot(unsigned slot , int state)
{
int sc = m_slot_sc[ slot ];
assert(sc >= 0);
m_io_sys->set_flg(uint8_t(sc) , state);
}
void hp9825_state::set_dmar_slot(unsigned slot , int state)
{
int sc = m_slot_sc[ slot ];
assert(sc >= 0);
m_io_sys->set_dmar(uint8_t(sc) , state);
}
MACHINE_CONFIG_START(hp9825_state::hp9825b)
HP_09825_67907(config , m_cpu , MAIN_CLOCK);
// Just guessing... settings borrowed from hp9845
m_cpu->set_rw_cycles(6 , 6);
m_cpu->set_relative_mode(false);
m_cpu->set_addrmap(AS_PROGRAM , &hp9825_state::cpu_mem_map);
m_cpu->set_addrmap(AS_IO , &hp9825_state::cpu_io_map);
m_cpu->set_irq_acknowledge_callback("io_sys" , FUNC(hp98x5_io_sys_device::irq_callback));
m_cpu->pa_changed_cb().set(m_io_sys , FUNC(hp98x5_io_sys_device::pa_w));
// Needed when 98035 RTC module is connected or time advances at about 1/4 the correct speed (NP misses a lot of 1kHz interrupts)
MCFG_QUANTUM_TIME(attotime::from_hz(5000));
HP98X5_IO_SYS(config , m_io_sys , 0);
m_io_sys->irl().set_inputline(m_cpu, HPHYBRID_IRL);
m_io_sys->irh().set_inputline(m_cpu, HPHYBRID_IRH);
m_io_sys->sts().set(m_cpu , FUNC(hp_09825_67907_cpu_device::status_w));
m_io_sys->flg().set(m_cpu , FUNC(hp_09825_67907_cpu_device::flag_w));
m_io_sys->dmar().set(m_cpu , FUNC(hp_09825_67907_cpu_device::dmar_w));
TIMER(config , m_cursor_timer , 0).configure_generic(timer_device::expired_delegate(FUNC(hp9825_state::cursor_blink) , this));
// Keyboard scan timer. A scan of the whole keyboard should take 2^14 KDP clocks.
TIMER(config , "kb_timer" , 0).configure_periodic(timer_device::expired_delegate(FUNC(hp9825_state::kb_scan) , this) , attotime::from_ticks(16384 , KDP_CLOCK));
// Tape drive
HP9825_TAPE(config , m_tape , 0);
m_tape->flg().set([this](int state) { m_io_sys->set_flg(TAPE_PA , state); });
m_tape->sts().set([this](int state) { m_io_sys->set_sts(TAPE_PA , state); });
m_tape->dmar().set([this](int state) { m_io_sys->set_dmar(TAPE_PA , state); });
// Printer
BITBANGER(config , m_prt_alpha_out , 0);
BITBANGER(config , m_prt_graph_out , 0);
TIMER(config , m_prt_timer , 0).configure_generic(timer_device::expired_delegate(FUNC(hp9825_state::prt_timer) , this));
// Beeper
SPEAKER(config, "mono").front_center();
BEEP(config, m_beeper, BEEPER_FREQ).add_route(ALL_OUTPUTS, "mono", 1.00);
TIMER(config , m_beep_timer , 0).configure_generic(timer_device::expired_delegate(FUNC(hp9825_state::beep_timer) , this));
// I/O slots
for (unsigned slot = 0; slot < 3; slot++) {
auto& finder = m_io_slot[ slot ];
hp9845_io_slot_device& tmp( HP9845_IO_SLOT(config , finder , 0) );
tmp.irq().set([this , slot](int state) { set_irq_slot(slot , state); });
tmp.sts().set([this , slot](int state) { set_sts_slot(slot , state); });
tmp.flg().set([this , slot](int state) { set_flg_slot(slot , state); });
tmp.dmar().set([this , slot](int state) { set_dmar_slot(slot , state); });
}
config.set_default_layout(layout_hp9825);
MACHINE_CONFIG_END
#define IOP_MASK(x) BIT_MASK<ioport_value>((x))
static INPUT_PORTS_START(hp9825)
// Keyboard is arranged in a 8 x 16 matrix. Of the 128 possible positions, 102 are used.
// Keys are mapped on bit b of KEYn
// where b = (row & 1) << 4 + column, n = row >> 1
// column = [0..15]
// row = [0..7]
// 4 more keys are not in the matrix: 2 SHIFTs, 1 SHIFT LOCK and RESET key.
// Fun fact: alphanumeric keys are arranged in the matrix so that their scancode (row/column number)
// equals the lower case ASCII code. The person in charge of routing the keyboard PCB
// must have loved this arrangement...
PORT_START("KEY0")
PORT_BIT(IOP_MASK(0) , IP_ACTIVE_HIGH , IPT_UNUSED) // 0,0: N/U
PORT_BIT(IOP_MASK(1) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC)) PORT_NAME("Stop") // 0,1: Stop
PORT_BIT(IOP_MASK(2) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("Rewind") // 0,2: Rewind
PORT_BIT(IOP_MASK(3) , IP_ACTIVE_HIGH , IPT_UNUSED) // 0,3: N/U
PORT_BIT(IOP_MASK(4) , IP_ACTIVE_HIGH , IPT_UNUSED) // 0,4: N/U
PORT_BIT(IOP_MASK(5) , IP_ACTIVE_HIGH , IPT_UNUSED) // 0,5: N/U
PORT_BIT(IOP_MASK(6) , IP_ACTIVE_HIGH , IPT_UNUSED) // 0,6: N/U
PORT_BIT(IOP_MASK(7) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("Result") // 0,7: Result
PORT_BIT(IOP_MASK(8) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("Line insert") // 0,8: Line insert
PORT_BIT(IOP_MASK(9) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("Line delete") // 0,9: Line delete
PORT_BIT(IOP_MASK(10) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_ENTER_PAD) PORT_CHAR(UCHAR_MAMEKEY(ENTER_PAD)) PORT_NAME("Execute") // 0,10: Execute
PORT_BIT(IOP_MASK(11) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("Line recall") // 0,11: Line recall
PORT_BIT(IOP_MASK(12) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("Run") // 0,12: Run
PORT_BIT(IOP_MASK(13) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("Store") // 0,13: Store
PORT_BIT(IOP_MASK(14) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("Display left") // 0,14: Display left
PORT_BIT(IOP_MASK(15) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("Display right") // 0,15: Display right
PORT_BIT(IOP_MASK(16) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) PORT_NAME("Display down") // 1,0: Display down
PORT_BIT(IOP_MASK(17) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP)) PORT_NAME("Display up") // 1,1: Display up
PORT_BIT(IOP_MASK(18) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_HOME) PORT_NAME("Clear") // 1,2: Clear
PORT_BIT(IOP_MASK(19) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("Print all") // 1,3: Print all
PORT_BIT(IOP_MASK(20) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_LEFT) PORT_NAME("Char back") // 1,4: Char back
PORT_BIT(IOP_MASK(21) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_RIGHT) PORT_NAME("Char forward") // 1,5: Char forward
PORT_BIT(IOP_MASK(22) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_INSERT) PORT_NAME("Char ins/rpl") // 1,6: Char ins/rpl
PORT_BIT(IOP_MASK(23) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_DEL) PORT_NAME("Char delete") // 1,7: Char delete
PORT_BIT(IOP_MASK(24) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("Step") // 1,8: Step
PORT_BIT(IOP_MASK(25) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_ENTER) PORT_NAME("Continue") PORT_CHAR(13) // 1,9: Continue
PORT_BIT(IOP_MASK(26) , IP_ACTIVE_HIGH , IPT_UNUSED) // 1,10: N/U
PORT_BIT(IOP_MASK(27) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("List") // 1,11: List
PORT_BIT(IOP_MASK(28) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("Line fetch") // 1,12: Line fetch
PORT_BIT(IOP_MASK(29) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("Erase") // 1,13: Erase
PORT_BIT(IOP_MASK(30) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("Record") // 1,14: Record
PORT_BIT(IOP_MASK(31) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("Load") // 1,15: Load
PORT_START("KEY1")
PORT_BIT(IOP_MASK(0) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') // 2,0: Space
PORT_BIT(IOP_MASK(1) , IP_ACTIVE_HIGH , IPT_UNUSED) // 2,1: N/U
PORT_BIT(IOP_MASK(2) , IP_ACTIVE_HIGH , IPT_UNUSED) // 2,2: N/U
PORT_BIT(IOP_MASK(3) , IP_ACTIVE_HIGH , IPT_UNUSED) // 2,3: N/U
PORT_BIT(IOP_MASK(4) , IP_ACTIVE_HIGH , IPT_UNUSED) // 2,4: N/U
PORT_BIT(IOP_MASK(5) , IP_ACTIVE_HIGH , IPT_UNUSED) // 2,5: N/U
PORT_BIT(IOP_MASK(6) , IP_ACTIVE_HIGH , IPT_UNUSED) // 2,6: N/U
PORT_BIT(IOP_MASK(7) , IP_ACTIVE_HIGH , IPT_UNUSED) // 2,7: N/U
PORT_BIT(IOP_MASK(8) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('(') PORT_NAME("Keypad (") // 2,8: KP (
PORT_BIT(IOP_MASK(9) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(')') PORT_NAME("Keypad )") // 2,9: KP )
PORT_BIT(IOP_MASK(10) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_ASTERISK) PORT_CHAR(UCHAR_MAMEKEY(ASTERISK)) // 2,10: KP *
PORT_BIT(IOP_MASK(11) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_PLUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(PLUS_PAD)) // 2,11: KP +
PORT_BIT(IOP_MASK(12) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<') // 2,12: ,
PORT_BIT(IOP_MASK(13) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_MINUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(MINUS_PAD)) // 2,13: KP -
PORT_BIT(IOP_MASK(14) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>') // 2,14: .
PORT_BIT(IOP_MASK(15) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_SLASH_PAD) PORT_CHAR(UCHAR_MAMEKEY(SLASH_PAD)) // 2,15: KP /
PORT_BIT(IOP_MASK(16) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR('\'') // 3,0: 0
PORT_BIT(IOP_MASK(17) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!') // 3,1: 1
PORT_BIT(IOP_MASK(18) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('"') // 3,2: 2
PORT_BIT(IOP_MASK(19) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#') // 3,3: 3
PORT_BIT(IOP_MASK(20) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$') // 3,4: 4
PORT_BIT(IOP_MASK(21) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%') // 3,5: 5
PORT_BIT(IOP_MASK(22) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('&') // 3,6: 6
PORT_BIT(IOP_MASK(23) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('@') // 3,7: 7
PORT_BIT(IOP_MASK(24) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('[') // 3,8: 8
PORT_BIT(IOP_MASK(25) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR(']') // 3,9: 9
PORT_BIT(IOP_MASK(26) , IP_ACTIVE_HIGH , IPT_UNUSED) // 3,10: N/U
PORT_BIT(IOP_MASK(27) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') // 3,11: ;
PORT_BIT(IOP_MASK(28) , IP_ACTIVE_HIGH , IPT_UNUSED) // 3,12: N/U
PORT_BIT(IOP_MASK(29) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_EQUALS_PAD) PORT_CHAR(UCHAR_MAMEKEY(EQUALS_PAD)) // 3,13: =
PORT_BIT(IOP_MASK(30) , IP_ACTIVE_HIGH , IPT_UNUSED) // 3,14: N/U
PORT_BIT(IOP_MASK(31) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('?') PORT_CHAR(':') // 3,15: ?
PORT_START("KEY2")
PORT_BIT(IOP_MASK(0) , IP_ACTIVE_HIGH , IPT_UNUSED) // 4,0: N/U
PORT_BIT(IOP_MASK(1) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("f0") // 4,1: f0
PORT_BIT(IOP_MASK(2) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1)) PORT_NAME("f1") // 4,2: f1
PORT_BIT(IOP_MASK(3) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2)) PORT_NAME("f2") // 4,3: f2
PORT_BIT(IOP_MASK(4) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3)) PORT_NAME("f3") // 4,4: f3
PORT_BIT(IOP_MASK(5) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4)) PORT_NAME("f4") // 4,5: f4
PORT_BIT(IOP_MASK(6) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5)) PORT_NAME("f5") // 4,6: f5
PORT_BIT(IOP_MASK(7) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6)) PORT_NAME("f6") // 4,7: f6
PORT_BIT(IOP_MASK(8) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_F7) PORT_CHAR(UCHAR_MAMEKEY(F7)) PORT_NAME("f7") // 4,8: f7
PORT_BIT(IOP_MASK(9) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_F8) PORT_CHAR(UCHAR_MAMEKEY(F8)) PORT_NAME("f8") // 4,9: f8
PORT_BIT(IOP_MASK(10) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_F9) PORT_CHAR(UCHAR_MAMEKEY(F9)) PORT_NAME("f9") // 4,10: f9
PORT_BIT(IOP_MASK(11) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_F10) PORT_CHAR(UCHAR_MAMEKEY(F10)) PORT_NAME("f10") // 4,11: f10
PORT_BIT(IOP_MASK(12) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_F11) PORT_CHAR(UCHAR_MAMEKEY(F11)) PORT_NAME("f11") // 4,12: f11
PORT_BIT(IOP_MASK(13) , IP_ACTIVE_HIGH , IPT_UNUSED) // 4,13: N/U
PORT_BIT(IOP_MASK(14) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_0_PAD) PORT_CHAR(UCHAR_MAMEKEY(0_PAD)) // 4,14: KP 0
PORT_BIT(IOP_MASK(15) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_1_PAD) PORT_CHAR(UCHAR_MAMEKEY(1_PAD)) // 4,15: KP 1
PORT_BIT(IOP_MASK(16) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_2_PAD) PORT_CHAR(UCHAR_MAMEKEY(2_PAD)) // 5,0: KP 2
PORT_BIT(IOP_MASK(17) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_3_PAD) PORT_CHAR(UCHAR_MAMEKEY(3_PAD)) // 5,1: KP 3
PORT_BIT(IOP_MASK(18) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_4_PAD) PORT_CHAR(UCHAR_MAMEKEY(4_PAD)) // 5,2: KP 4
PORT_BIT(IOP_MASK(19) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_5_PAD) PORT_CHAR(UCHAR_MAMEKEY(5_PAD)) // 5,3: KP 5
PORT_BIT(IOP_MASK(20) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_6_PAD) PORT_CHAR(UCHAR_MAMEKEY(6_PAD)) // 5,4: KP 6
PORT_BIT(IOP_MASK(21) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_7_PAD) PORT_CHAR(UCHAR_MAMEKEY(7_PAD)) // 5,5: KP 7
PORT_BIT(IOP_MASK(22) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_8_PAD) PORT_CHAR(UCHAR_MAMEKEY(8_PAD)) // 5,6: KP 8
PORT_BIT(IOP_MASK(23) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_9_PAD) PORT_CHAR(UCHAR_MAMEKEY(9_PAD)) // 5,7: KP 9
PORT_BIT(IOP_MASK(24) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_DEL_PAD) PORT_CHAR(UCHAR_MAMEKEY(DEL_PAD)) // 5,8: KP .
PORT_BIT(IOP_MASK(25) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_COMMA_PAD) PORT_CHAR(UCHAR_MAMEKEY(COMMA_PAD)) // 5,9: KP ,
PORT_BIT(IOP_MASK(26) , IP_ACTIVE_HIGH , IPT_UNUSED) // 5,10: N/U
PORT_BIT(IOP_MASK(27) , IP_ACTIVE_HIGH , IPT_UNUSED) // 5,11: N/U
PORT_BIT(IOP_MASK(28) , IP_ACTIVE_HIGH , IPT_UNUSED) // 5,12: N/U
PORT_BIT(IOP_MASK(29) , IP_ACTIVE_HIGH , IPT_UNUSED) // 5,13: N/U
PORT_BIT(IOP_MASK(30) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_QUOTE) PORT_NAME(u8"\u2191 \u221A") // 5,14: ^ (↑ √)
PORT_BIT(IOP_MASK(31) , IP_ACTIVE_HIGH , IPT_UNUSED) // 5,15: N/U
PORT_START("KEY3")
PORT_BIT(IOP_MASK(0) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("Enter exp _") // 6,0: Enter exp
PORT_BIT(IOP_MASK(1) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A') // 6,1: A
PORT_BIT(IOP_MASK(2) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B') // 6,2: B
PORT_BIT(IOP_MASK(3) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C') // 6,3: C
PORT_BIT(IOP_MASK(4) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D') // 6,4: D
PORT_BIT(IOP_MASK(5) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E') // 6,5: E
PORT_BIT(IOP_MASK(6) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F') // 6,6: F
PORT_BIT(IOP_MASK(7) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G') // 6,7: G
PORT_BIT(IOP_MASK(8) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H') // 6,8: H
PORT_BIT(IOP_MASK(9) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I') // 6,9: I
PORT_BIT(IOP_MASK(10) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J') // 6,10: J
PORT_BIT(IOP_MASK(11) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K') // 6,11: K
PORT_BIT(IOP_MASK(12) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L') // 6,12: L
PORT_BIT(IOP_MASK(13) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M') // 6,13: M
PORT_BIT(IOP_MASK(14) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N') // 6,14: N
PORT_BIT(IOP_MASK(15) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O') // 6,15: O
PORT_BIT(IOP_MASK(16) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P') // 7,0: P
PORT_BIT(IOP_MASK(17) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q') // 7,1: Q
PORT_BIT(IOP_MASK(18) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R') // 7,2: R
PORT_BIT(IOP_MASK(19) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S') // 7,3: S
PORT_BIT(IOP_MASK(20) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T') // 7,4: T
PORT_BIT(IOP_MASK(21) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U') // 7,5: U
PORT_BIT(IOP_MASK(22) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V') // 7,6: V
PORT_BIT(IOP_MASK(23) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W') // 7,7: W
PORT_BIT(IOP_MASK(24) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X') // 7,8: X
PORT_BIT(IOP_MASK(25) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y') // 7,9: Y
PORT_BIT(IOP_MASK(26) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z') // 7,10: Z
PORT_BIT(IOP_MASK(27) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME(u8"π |") // 7,11: Pi
PORT_BIT(IOP_MASK(28) , IP_ACTIVE_HIGH , IPT_UNUSED) // 7,12: N/U
PORT_BIT(IOP_MASK(29) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_END) PORT_NAME(u8"\u2192") // 7,13: Gazinta (→)
PORT_BIT(IOP_MASK(30) , IP_ACTIVE_HIGH , IPT_UNUSED) // 7,14: N/U
PORT_BIT(IOP_MASK(31) , IP_ACTIVE_HIGH , IPT_UNUSED) // 7,15: N/U
PORT_START("KEY_SHIFT")
PORT_BIT(IOP_MASK(0) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1) // Shift
INPUT_PORTS_END
ROM_START(hp9825b)
ROM_REGION(0xa000 , "cpu" , ROMREGION_16BIT | ROMREGION_BE)
ROM_LOAD("sysrom1.bin" , 0x0000 , 0x2000 , CRC(fe429268) SHA1(f2fe7c5abca92bd13f81b4385fc4fce0cafb0da0))
ROM_LOAD("sysrom2.bin" , 0x2000 , 0x2000 , CRC(96093b5d) SHA1(c6ec4cafd019887df0fa849b3c7070bb74faee54))
ROM_LOAD("sysrom3.bin" , 0x4000 , 0x2000 , CRC(f9470f67) SHA1(b80cb4a366d93bd7acc3508ce987bb11c5986b2a))
ROM_LOAD("genio_t.bin" , 0x6800 , 0x0800 , CRC(ade1d1ed) SHA1(9af74a65b29ef1885f74164238ecf8d16ac995d6))
ROM_LOAD("plot72.bin" , 0x7000 , 0x0800 , CRC(0a9cb8db) SHA1(d0d126fca108f2715e1e408cb31b09ba69385ac4))
ROM_LOAD("advpgm_t.bin", 0x8000 , 0x0800 , CRC(965b5e5a) SHA1(ff44dd15f8fa4ca03dfd970ed8b200e8a071ec13))
ROM_LOAD("extio_t.bin" , 0x8800 , 0x1000 , CRC(a708b978) SHA1(baf53c8a2b24d059f95252baf1452188eaf6e4be))
ROM_LOAD("strings_t.bin",0x9800 , 0x0800 , CRC(b5ca5da5) SHA1(af13abb3c15836c566863c656e1659f7e6f96d04))
ROM_END
// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS
COMP(1980, hp9825b, 0, 0, hp9825b, hp9825, hp9825_state, empty_init, "Hewlett-Packard", "HP 9825B", 0)