diff options
Diffstat (limited to 'src/mame/drivers/hp9825.cpp')
-rw-r--r-- | src/mame/drivers/hp9825.cpp | 115 |
1 files changed, 111 insertions, 4 deletions
diff --git a/src/mame/drivers/hp9825.cpp b/src/mame/drivers/hp9825.cpp index b04967f41c1..e61a49f7177 100644 --- a/src/mame/drivers/hp9825.cpp +++ b/src/mame/drivers/hp9825.cpp @@ -14,12 +14,12 @@ // - Keyboard (SHIFT LOCK & RESET not implemented) // - Display & run light // - DC100 tape drive +// - Printer +// - Beeper // What's not yet in: // - Internal & external expansion ROMs // - Configurable RAM size -// - Printer // - I/O expansion slots: 98034 & 98035 modules from hp9845 emulation can be used here, too -// - Beeper // // 9825A & 9825T can also be emulated. At the moment I haven't all the necessary // ROM dumps, though. @@ -28,6 +28,9 @@ #include "cpu/hphybrid/hphybrid.h" #include "machine/timer.h" #include "machine/hp9825_tape.h" +#include "imagedev/bitbngr.h" +#include "speaker.h" +#include "sound/beep.h" #include "hp9825.lh" // CPU clock (generated by a trimmered RC oscillator) @@ -40,6 +43,15 @@ constexpr unsigned KDP_CLOCK = MAIN_CLOCK / 4; constexpr uint8_t KDP_PA = 0; constexpr uint8_t TAPE_PA = 1; +// 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) @@ -68,6 +80,11 @@ public: , 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_display(*this , "char_%u_%u" , 0U , 0U) , m_run_light(*this , "run_light") { @@ -81,6 +98,11 @@ private: 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; output_finder<32 , 7> m_display; output_finder<> m_run_light; @@ -100,6 +122,10 @@ private: uint8_t m_pa; uint16_t m_flg_status; uint16_t m_sts_status; + // Printer + uint8_t m_printer_mem[ 16 ]; + uint8_t m_printer_idx; + unsigned m_printer_line; // 0: printer idle, 1..10: line being printed virtual void machine_start() override; virtual void machine_reset() override; @@ -111,6 +137,7 @@ private: 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); @@ -125,6 +152,10 @@ private: void update_flg_sts(); void set_sts(uint8_t sc , int state); void set_flg(uint8_t sc , int state); + + TIMER_DEVICE_CALLBACK_MEMBER(prt_timer); + + TIMER_DEVICE_CALLBACK_MEMBER(beep_timer); }; void hp9825_state::machine_start() @@ -158,6 +189,11 @@ void hp9825_state::machine_reset() m_pa = 0; m_flg_status = 0; m_sts_status = 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) @@ -165,6 +201,7 @@ 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: } @@ -202,8 +239,15 @@ WRITE16_MEMBER(hp9825_state::disp_w) READ16_MEMBER(hp9825_state::kdp_status_r) { - // TODO: - return 8; + uint16_t res = 8; + if (BIT(m_irl_pending, KDP_PA)) { + BIT_SET(res , 4); + } + if (m_printer_line) { + BIT_SET(res , 2); + } + + return res; } WRITE16_MEMBER(hp9825_state::kdp_control_w) @@ -234,11 +278,33 @@ WRITE16_MEMBER(hp9825_state::kdp_control_w) } 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 ] = { @@ -546,6 +612,37 @@ void hp9825_state::set_flg(uint8_t sc , int state) } } +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); +} + MACHINE_CONFIG_START(hp9825_state::hp9825b) HP_09825_67907(config , m_cpu , MAIN_CLOCK); // Just guessing... settings borrowed from hp9845 @@ -567,6 +664,16 @@ MACHINE_CONFIG_START(hp9825_state::hp9825b) m_tape->sts().set([this , sc = TAPE_PA](int state) { set_sts(sc , state); }); m_tape->dmar().set(m_cpu , FUNC(hp_09825_67907_cpu_device::dmar_w)); + // 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)); + config.set_default_layout(layout_hp9825); MACHINE_CONFIG_END |