From 8da1c539662bd567f3881fa1118f11bdeffeb31e Mon Sep 17 00:00:00 2001 From: fulivi Date: Thu, 17 Feb 2022 03:48:41 +0100 Subject: hp9825: printer output on a screen added, cassette status added (#9230) --- src/mame/drivers/hp9825.cpp | 107 ++++++++++++++++++++++++++++++++++++--- src/mame/machine/hp9825_tape.cpp | 9 +++- src/mame/machine/hp9825_tape.h | 2 + 3 files changed, 109 insertions(+), 9 deletions(-) diff --git a/src/mame/drivers/hp9825.cpp b/src/mame/drivers/hp9825.cpp index 90a88709257..d4f373b3051 100644 --- a/src/mame/drivers/hp9825.cpp +++ b/src/mame/drivers/hp9825.cpp @@ -47,6 +47,7 @@ #include "bus/hp9845_io/hp9845_io.h" #include "imagedev/bitbngr.h" #include "speaker.h" +#include "screen.h" #include "sound/beep.h" #include "hp9825.lh" #include "softlist_dev.h" @@ -54,6 +55,8 @@ // Debugging #define VERBOSE 0 #include "logmacro.h" +#define LOG_DBG_MASK (LOG_GENERAL << 1) +#define LOG_DBG(...) LOGMASKED(LOG_DBG_MASK, __VA_ARGS__) // CPU clock (generated by a trimmered RC oscillator) constexpr unsigned MAIN_CLOCK = 6000000; @@ -71,6 +74,25 @@ constexpr uint8_t IO_SLOT_LAST_PA = 15; // This value is semi-guessed. constexpr unsigned KDP_CLOCKS_PER_LINE = 50000; +// Printer constants +constexpr unsigned PRINT_MATRIX_H = 7; +constexpr unsigned PRINT_EMPTY_TOP = 1; +constexpr unsigned PRINT_EMPTY_BOT = 2; +constexpr unsigned PRINT_CELL_H = PRINT_MATRIX_H + PRINT_EMPTY_TOP + PRINT_EMPTY_BOT; +constexpr unsigned PRINT_MATRIX_W = 5; +constexpr unsigned PRINT_EMPTY_R = 2; +constexpr unsigned PRINT_CELL_W = PRINT_MATRIX_W + PRINT_EMPTY_R; +constexpr unsigned PRINT_COLUMNS = 16; +constexpr unsigned PRINT_PIXELS_ROW = PRINT_COLUMNS * PRINT_CELL_W - PRINT_EMPTY_R; +constexpr unsigned PRINT_WIN_ROWS = 6; +constexpr unsigned PRINT_WINDOWS = 4; +constexpr unsigned PRINT_WIN_H = PRINT_WIN_ROWS * PRINT_CELL_H; +constexpr unsigned PRINT_WIN_W = PRINT_PIXELS_ROW; +constexpr unsigned PRINT_OUT_H = PRINT_WIN_H * PRINT_WINDOWS; +constexpr unsigned PRINT_OUT_W = PRINT_PIXELS_ROW; +constexpr uint32_t PRINT_BG = 0xffffff; // White +constexpr uint32_t PRINT_FG = 0x2d1881; // Blue-violet + // Beeper constants // Values come from R/C values on schematics constexpr unsigned BEEPER_FREQ = 1400; @@ -109,22 +131,29 @@ public: , m_tape(*this , "tape") , m_io_key(*this , "KEY%u" , 0) , m_shift_key(*this , "KEY_SHIFT") + , m_scroll_key(*this , "KEY_SCROLL") , 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_prt_out(*this, "printer") , m_display(*this , "char_%u_%u" , 0U , 0U) , m_run_light(*this , "run_light") , m_shift_lock(*this , "shift_lock") , m_tape_led(*this , "tape_led") + , m_cassette(*this , "cassette") + , m_printer_bitmap(PRINT_OUT_W , PRINT_OUT_H) { } void hp9825_base(machine_config &config); DECLARE_INPUT_CHANGED_MEMBER(kb_changed); + DECLARE_INPUT_CHANGED_MEMBER(scroll_changed); + + uint32_t printer_out_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); protected: virtual void machine_start() override; @@ -140,16 +169,19 @@ private: required_device m_tape; required_ioport_array<4> m_io_key; required_ioport m_shift_key; + required_ioport m_scroll_key; required_device m_prt_alpha_out; required_device m_prt_graph_out; required_device m_prt_timer; required_device m_beeper; required_device m_beep_timer; required_device_array m_io_slot; + required_device m_prt_out; output_finder<32 , 7> m_display; output_finder<> m_run_light; output_finder<> m_shift_lock; output_finder<> m_tape_led; + output_finder<> m_cassette; bool m_display_on; uint8_t m_display_mem[ 32 ]; @@ -162,9 +194,11 @@ private: bool m_autorepeating; unsigned m_autorepeat_cnt; // Printer - uint8_t m_printer_mem[ 16 ]; + uint8_t m_printer_mem[ PRINT_COLUMNS ]; uint8_t m_printer_idx; unsigned m_printer_line; // 0: printer idle, 1..10: line being printed + bitmap_rgb32 m_printer_bitmap; + unsigned m_printer_window; // 0 is bottom window (the one closer to printhead) // SC of slots int m_slot_sc[ 3 ]; @@ -198,6 +232,10 @@ void hp9825_state::machine_start() m_run_light.resolve(); m_shift_lock.resolve(); m_tape_led.resolve(); + m_cassette.resolve(); + + m_printer_bitmap.fill(PRINT_BG); + m_printer_window = 0; save_item(NAME(m_display_on)); save_item(NAME(m_display_mem)); @@ -345,7 +383,7 @@ void hp9825_state::kdp_control_w(uint16_t data) void hp9825_state::printer_w(uint16_t data) { m_printer_mem[ m_printer_idx ] = uint8_t(data); - m_printer_idx = (m_printer_idx + 1) & 0xf; + m_printer_idx = (m_printer_idx + 1) % PRINT_COLUMNS; } // The character generator was reverse engineered from images of printer & display test patterns. @@ -596,6 +634,26 @@ INPUT_CHANGED_MEMBER(hp9825_state::kb_changed) } } +INPUT_CHANGED_MEMBER(hp9825_state::scroll_changed) +{ + LOG_DBG("scroll p=%d n=%d\n" , param , newval); + switch (param) { + case 0: + // Scroll up + if (newval && m_printer_window > 0) { + m_printer_window--; + } + break; + + case 1: + // Scroll down + if (newval && m_printer_window < (PRINT_WINDOWS - 1)) { + m_printer_window++; + } + break; + } +} + 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) { @@ -612,16 +670,31 @@ void hp9825_state::kb_scan_ioport(ioport_value pressed , ioport_port &port , uns TIMER_DEVICE_CALLBACK_MEMBER(hp9825_state::prt_timer) { - if (m_printer_line == 1 || m_printer_line == 9 || m_printer_line == 10) { + // Shift printer bitmap one line up and clear bottom line + { + bitmap_rgb32 tmp{ m_printer_bitmap.width() , m_printer_bitmap.height() }; + s32 scroll = -1; + rectangle cliprect{ 0 , m_printer_bitmap.width() - 1 , 0 , m_printer_bitmap.height() - 2 }; + copyscrollbitmap(tmp , m_printer_bitmap , 0 , nullptr , 1 , &scroll , cliprect); + copybitmap(m_printer_bitmap , tmp , 0 , 0 , 0 , 0 , cliprect); + m_printer_bitmap.plot_box(0 , m_printer_bitmap.height() - 1 , m_printer_bitmap.width() , 1 , PRINT_BG); + } + + if ((m_printer_line > 0 && m_printer_line <= PRINT_EMPTY_TOP) || + (m_printer_line > (PRINT_EMPTY_TOP + PRINT_MATRIX_H) && m_printer_line <= PRINT_CELL_H)) { // Empty lines - for (unsigned i = 0; i < 110; i++) { + for (unsigned i = 0; i < PRINT_PIXELS_ROW; i++) { m_prt_graph_out->output(' '); } } else { - for (unsigned i = 0; i < 16; i++) { - for (unsigned col = 0; col < 5; col++) { + for (unsigned i = 0; i < PRINT_COLUMNS; i++) { + for (unsigned col = 0; col < PRINT_MATRIX_W; col++) { uint8_t pixels = chargen[ m_printer_mem[ i ] & 0x7f ][ col ]; - m_prt_graph_out->output(BIT(pixels , m_printer_line - 2) ? '*' : ' '); + bool pixel = BIT(pixels , m_printer_line - PRINT_EMPTY_TOP - 1); + m_prt_graph_out->output(pixel ? '*' : ' '); + if (pixel) { + m_printer_bitmap.pix(m_printer_bitmap.height() - 1 , i * PRINT_CELL_W + col) = PRINT_FG; + } } m_prt_graph_out->output(' '); m_prt_graph_out->output(' '); @@ -629,13 +702,21 @@ TIMER_DEVICE_CALLBACK_MEMBER(hp9825_state::prt_timer) } m_prt_graph_out->output('\n'); m_printer_line++; - if (m_printer_line <= 10) { + if (m_printer_line <= PRINT_CELL_H) { m_prt_timer->adjust(attotime::from_ticks(KDP_CLOCKS_PER_LINE , KDP_CLOCK)); } else { m_printer_line = 0; } } +uint32_t hp9825_state::printer_out_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + s32 scroll = -s32((PRINT_WINDOWS - m_printer_window - 1) * PRINT_WIN_H); + copyscrollbitmap(bitmap , m_printer_bitmap , 0 , nullptr , 1 , &scroll , cliprect); + + return 0; +} + TIMER_DEVICE_CALLBACK_MEMBER(hp9825_state::beep_timer) { m_beeper->set_state(0); @@ -700,11 +781,17 @@ void hp9825_state::hp9825_base(machine_config &config) 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); }); m_tape->led().set([this](int state) { m_tape_led = state; }); + m_tape->cart_in().set([this](int state) { if (started()) m_cassette = state; }); // Printer BITBANGER(config , m_prt_alpha_out , 0); BITBANGER(config , m_prt_graph_out , 0); TIMER(config , m_prt_timer , 0).configure_generic(FUNC(hp9825_state::prt_timer)); + SCREEN(config , m_prt_out , SCREEN_TYPE_RASTER); + m_prt_out->set_screen_update(FUNC(hp9825_state::printer_out_update)); + m_prt_out->set_refresh_hz(60); + m_prt_out->set_size(PRINT_WIN_W, PRINT_WIN_H); + m_prt_out->set_visarea_full(); // Beeper SPEAKER(config, "mono").front_center(); @@ -881,6 +968,10 @@ static INPUT_PORTS_START(hp9825) PORT_BIT(IOP_MASK(0) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1) PORT_CHANGED_MEMBER(DEVICE_SELF, hp9825_state, kb_changed, 0) // Left and right Shift PORT_BIT(IOP_MASK(1) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("Shift lock") PORT_CHANGED_MEMBER(DEVICE_SELF, hp9825_state, kb_changed, 1) // Shift lock PORT_BIT(IOP_MASK(2) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("Reset") PORT_CHANGED_MEMBER(DEVICE_SELF, hp9825_state, kb_changed, 2) // Reset + + PORT_START("KEY_SCROLL") + PORT_BIT(IOP_MASK(0) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("Scroll up") PORT_CHANGED_MEMBER(DEVICE_SELF, hp9825_state, scroll_changed, 0) + PORT_BIT(IOP_MASK(1) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("Scroll down") PORT_CHANGED_MEMBER(DEVICE_SELF, hp9825_state, scroll_changed, 1) INPUT_PORTS_END // +---------------+ diff --git a/src/mame/machine/hp9825_tape.cpp b/src/mame/machine/hp9825_tape.cpp index dd85bdfbe09..402d6f5ef44 100644 --- a/src/mame/machine/hp9825_tape.cpp +++ b/src/mame/machine/hp9825_tape.cpp @@ -20,7 +20,8 @@ #define LOG_DBG(...) LOGMASKED(LOG_DBG_MASK, __VA_ARGS__) #undef VERBOSE //#define VERBOSE (LOG_GENERAL | LOG_REG_MASK | LOG_DBG_MASK) -#define VERBOSE (LOG_GENERAL) +//#define VERBOSE (LOG_GENERAL) +#define VERBOSE (LOG_GENERAL | LOG_DBG_MASK) // Bit manipulation namespace { @@ -80,6 +81,7 @@ hp9825_tape_device::hp9825_tape_device(const machine_config &mconfig, const char , m_sts_handler(*this) , m_dmar_handler(*this) , m_led_handler(*this) + , m_cart_in_handler(*this) , m_tape(*this , "drive") , m_short_gap_timer(*this , "short_tmr") , m_long_gap_timer(*this , "long_tmr") @@ -119,10 +121,12 @@ void hp9825_tape_device::device_add_mconfig(machine_config &config) void hp9825_tape_device::device_start() { + LOG_DBG("start\n"); m_flg_handler.resolve_safe(); m_sts_handler.resolve_safe(); m_dmar_handler.resolve_safe(); m_led_handler.resolve_safe(); + m_cart_in_handler.resolve_safe(); save_item(NAME(m_cmd_reg)); save_item(NAME(m_stat_reg)); @@ -143,6 +147,7 @@ void hp9825_tape_device::device_start() void hp9825_tape_device::device_reset() { + LOG_DBG("reset\n"); clear_state(); } @@ -327,6 +332,8 @@ WRITE_LINE_MEMBER(hp9825_tape_device::cart_out_w) BIT_CLR(m_stat_reg, STAT_REG_WPR_BIT); } + m_cart_in_handler(!state); + update_sts(); } diff --git a/src/mame/machine/hp9825_tape.h b/src/mame/machine/hp9825_tape.h index 6e7ebd2668c..768a29fde7a 100644 --- a/src/mame/machine/hp9825_tape.h +++ b/src/mame/machine/hp9825_tape.h @@ -30,6 +30,7 @@ public: auto sts() { return m_sts_handler.bind(); } auto dmar() { return m_dmar_handler.bind(); } auto led() { return m_led_handler.bind(); } + auto cart_in() { return m_cart_in_handler.bind(); } DECLARE_WRITE_LINE_MEMBER(short_gap_w); DECLARE_WRITE_LINE_MEMBER(long_gap_w); @@ -52,6 +53,7 @@ private: devcb_write_line m_sts_handler; devcb_write_line m_dmar_handler; devcb_write_line m_led_handler; + devcb_write_line m_cart_in_handler; required_device m_tape; required_device m_short_gap_timer; // U43a -- cgit v1.2.3