From 8eedab96df50e9b3bfe928838f144913a253a99d Mon Sep 17 00:00:00 2001 From: fulivi Date: Tue, 11 Apr 2017 16:32:56 +0200 Subject: [PATCH] hp9845: driver for HP9845T added (in collaboration with A.Kueckes) --- src/mame/drivers/hp9845.cpp | 1103 +++++++++++++++++++++++++++++++---- src/mame/includes/hp9845.h | 3 - 2 files changed, 993 insertions(+), 113 deletions(-) diff --git a/src/mame/drivers/hp9845.cpp b/src/mame/drivers/hp9845.cpp index 41bf605fd3a..e4760b9ecfb 100644 --- a/src/mame/drivers/hp9845.cpp +++ b/src/mame/drivers/hp9845.cpp @@ -60,6 +60,11 @@ #define BIT_CLR(w , n) ((w) &= ~BIT_MASK(n)) #define BIT_SET(w , n) ((w) |= BIT_MASK(n)) +// The FLG behavior in real 98780A hw apparently doesn't match what's +// documented in Tony Duell's schematics. +// The following macro selects the FLG behavior implemented by this driver. +#define HP98780A_REAL_HW + /* The 9845 has three possible display options: @@ -151,20 +156,31 @@ // Constants of 98770A video // HBEND & VBEND probably are not really 0 -#define VIDEO_770_PIXEL_CLOCK 29798400 -#define VIDEO_770_HTOTAL 1024 -#define VIDEO_770_HBEND 0 -#define VIDEO_770_HBSTART (VIDEO_CHAR_COLUMNS * VIDEO_CHAR_WIDTH) -#define VIDEO_770_VTOTAL 485 -#define VIDEO_770_VBEND 0 -#define VIDEO_770_VBSTART (VIDEO_770_VBEND + GVIDEO_VPIXELS) -#define VIDEO_770_ALPHA_L_LIM 80 // Left-side limit of alpha-only horizontal part -#define VIDEO_770_ALPHA_R_LIM 640 // Right-side limit of alpha-only horizontal part +#define VIDEO_770_PIXEL_CLOCK 29798400 +#define VIDEO_770_HTOTAL 1024 +#define VIDEO_770_HBEND 0 +#define VIDEO_770_HBSTART (VIDEO_CHAR_COLUMNS * VIDEO_CHAR_WIDTH) +#define VIDEO_770_VTOTAL 485 +#define VIDEO_770_VBEND 0 +#define VIDEO_770_VBSTART (VIDEO_770_VBEND + GVIDEO_VPIXELS) +#define VIDEO_770_ALPHA_L_LIM 80 // Left-side limit of alpha-only horizontal part +#define VIDEO_770_ALPHA_R_LIM 640 // Right-side limit of alpha-only horizontal part -#define I_GR 0xb0 // graphics intensity -#define I_AL 0xd0 // alpha intensity -#define I_CU 0xf0 // graphics cursor intensity -#define I_LP 0xff // light pen cursor intensity +// Constants of 98780A video +#define VIDEO_780_PIXEL_CLOCK 28224000 +#define VIDEO_780_HTOTAL 896 +#define VIDEO_780_VTOTAL 525 +#define VIDEO_780_HBEND 0 +#define VIDEO_780_HBSTART (VIDEO_CHAR_COLUMNS * VIDEO_CHAR_WIDTH) +#define VIDEO_780_VBEND 0 +#define VIDEO_780_VBSTART (VIDEO_780_VBEND + GVIDEO_VPIXELS) +#define VIDEO_780_ALPHA_L_LIM 80 // Left-side limit of alpha-only horizontal part +#define VIDEO_780_ALPHA_R_LIM 640 // Right-side limit of alpha-only horizontal part + +#define I_GR 0xb0 // graphics intensity +#define I_AL 0xd0 // alpha intensity +#define I_CU 0xf0 // graphics cursor intensity +#define I_LP 0xff // light pen cursor intensity // Palette indexes (for monochromatic screens) #define PEN_BLACK 0 // Black @@ -178,9 +194,9 @@ constexpr unsigned LP_FOV = 9; // Field of view constexpr unsigned LP_XOFFSET = 5; // x-offset of LP (due to delay in hit recognition) // Peripheral Addresses (PA) -#define IO_SLOT_FIRST_PA 1 -#define IO_SLOT_LAST_PA 12 -#define T15_PA 15 +#define IO_SLOT_FIRST_PA 1 +#define IO_SLOT_LAST_PA 12 +#define T15_PA 15 #define KEY_SCAN_OSCILLATOR 327680 @@ -368,8 +384,7 @@ hp9845_base_state::hp9845_base_state(const machine_config &mconfig, device_type m_io_slot2(*this , "slot2"), m_io_slot3(*this , "slot3"), m_ram(*this , RAM_TAG), - m_chargen(*this , "chargen"), - m_optional_chargen(*this , "optional_chargen") + m_chargen(*this , "chargen") { } @@ -725,13 +740,17 @@ protected: virtual void advance_gv_fsm(bool ds , bool trigger) override; void update_graphic_bits(void); + // Optional character generator + required_region_ptr m_optional_chargen; + uint8_t m_video_attr; uint16_t m_gv_cursor_w; // U38 & U39 (GS) std::vector m_graphic_mem; }; hp9845b_state::hp9845b_state(const machine_config &mconfig, device_type type, const char *tag) - : hp9845_base_state(mconfig , type , tag) + : hp9845_base_state(mconfig , type , tag), + m_optional_chargen(*this , "optional_chargen") { } @@ -1245,7 +1264,7 @@ INPUT_PORTS_END class hp9845ct_state : public hp9845_base_state { public: - hp9845ct_state(const machine_config &mconfig, device_type type, const char *tag, unsigned v_total); + hp9845ct_state(const machine_config &mconfig, device_type type, const char *tag); virtual void machine_start() override; virtual void machine_reset() override; @@ -1265,8 +1284,9 @@ protected: virtual void plot(uint16_t x, uint16_t y, bool draw_erase) = 0; void draw_line(unsigned x0 , unsigned y0 , unsigned x1 , unsigned y1); void update_line_pattern(void); + void pattern_fill(uint16_t x0 , uint16_t y0 , uint16_t x1 , uint16_t y1 , unsigned fill_idx); static uint16_t get_gv_mem_addr(unsigned x , unsigned y); - void update_graphic_bits(void); + virtual void update_graphic_bits(void) = 0; int get_lp_cursor_y_top(void) const; void render_lp_cursor(unsigned video_scanline , unsigned pen_idx); @@ -1316,18 +1336,16 @@ protected: bool m_gv_lp_int_en; bool m_gv_lp_hit_lt192; bool m_gv_lp_int_256; - const unsigned m_gv_v_total; static const uint16_t m_line_type[]; static const uint16_t m_area_fill[]; }; -hp9845ct_state::hp9845ct_state(const machine_config &mconfig, device_type type, const char *tag, unsigned v_total) +hp9845ct_state::hp9845ct_state(const machine_config &mconfig, device_type type, const char *tag) : hp9845_base_state(mconfig , type , tag), m_lightpen_x(*this, "LIGHTPENX"), m_lightpen_y(*this, "LIGHTPENY"), - m_lightpen_sw(*this, "GKEY"), - m_gv_v_total(v_total) + m_lightpen_sw(*this, "GKEY") { } @@ -1522,48 +1540,40 @@ void hp9845ct_state::update_line_pattern(void) } } +void hp9845ct_state::pattern_fill(uint16_t x0 , uint16_t y0 , uint16_t x1 , uint16_t y1 , unsigned fill_idx) +{ + uint16_t x,y,xmax,ymax; + uint16_t pixel_mask, fill_mask; + + x = std::min(x0 , x1); + xmax = std::max(x0 , x1); + y = std::min(y0 , y1); + ymax = std::max(y0 , y1); + + for (;y <= ymax; y++) { + fill_mask = (m_area_fill[ fill_idx ] << (y % 4) * 4) & 0xf000; + fill_mask |= (fill_mask >> 4) | (fill_mask >> 8) | (fill_mask >> 12); + for (;x <= xmax; x++) { + pixel_mask = (0x8000 >> (x % 16)); + plot(x , y , (pixel_mask & fill_mask) != 0); + } + } +} + uint16_t hp9845ct_state::get_gv_mem_addr(unsigned x , unsigned y) { return (uint16_t)((x + y * 35) & GVIDEO_ADDR_MASK); } -void hp9845ct_state::update_graphic_bits(void) -{ - bool gv_ready = m_gv_lp_int_en && m_gv_lp_status; - - if (m_gv_gr_en && !gv_ready) { - gv_ready = m_gv_fsm_state == GV_STAT_WAIT_DS_0 || - m_gv_fsm_state == GV_STAT_WAIT_TRIG_0 || - m_gv_fsm_state == GV_STAT_WAIT_DS_1 || - m_gv_fsm_state == GV_STAT_WAIT_DS_2 || - m_gv_fsm_state == GV_STAT_WAIT_TRIG_1; - } - - flg_w(GVIDEO_PA , gv_ready); - - bool irq = m_gv_int_en && !m_gv_dma_en && gv_ready; - -#if 0 - // DEBUG DEBUG DEBUG - static bool last_irq = false; - if (!last_irq && irq) { - logerror("GV IRQ %d %d\n" , m_gv_lp_int_en , m_gv_lp_status); - } - last_irq = irq; -#endif - - irq_w(GVIDEO_PA , irq); - - bool dmar = gv_ready && m_gv_dma_en; - - m_ppu->dmar_w(dmar); -} - int hp9845ct_state::get_lp_cursor_y_top(void) const { + // The 770's VTOTAL applies to 780, too. + // The 780 hw generates a line clock (GVclk in Duell's schematics) that's suppressed + // for lines in [485..524] range so that the total number of lines per frame counted + // by this clock matches the total count of lines in 770 (i.e. 485). int wrapped_cursor_y = m_gv_lp_cursor_y; - if (wrapped_cursor_y >= GVIDEO_VPIXELS && wrapped_cursor_y < m_gv_v_total) { - wrapped_cursor_y -= m_gv_v_total; + if (wrapped_cursor_y >= GVIDEO_VPIXELS && wrapped_cursor_y < VIDEO_770_VTOTAL) { + wrapped_cursor_y -= VIDEO_770_VTOTAL; } return wrapped_cursor_y; @@ -1890,17 +1900,20 @@ protected: void video_render_buff(unsigned video_scanline , unsigned line_in_row, bool buff_idx); void graphic_video_render(unsigned video_scanline); virtual void plot(uint16_t x, uint16_t y, bool draw_erase) override; - void pattern_fill(uint16_t x0 , uint16_t y0 , uint16_t x1 , uint16_t y1); void check_io_counter_restore(void); void advance_io_counter(void); virtual void advance_gv_fsm(bool ds , bool trigger) override; + virtual void update_graphic_bits(void) override; // Palette indexes static constexpr unsigned pen_graphic(unsigned rgb) { return rgb; } static constexpr unsigned pen_alpha(unsigned rgb) { return 8 + rgb; } static constexpr unsigned pen_cursor(unsigned rgb) { return 16 + rgb; } + // Optional character generator + required_region_ptr m_optional_chargen; + std::vector m_graphic_mem[ 3 ]; uint16_t m_gv_music_memory; uint8_t m_gv_cursor_color; @@ -1909,7 +1922,8 @@ protected: }; hp9845c_state::hp9845c_state(const machine_config &mconfig, device_type type, const char *tag) - : hp9845ct_state(mconfig , type , tag, VIDEO_770_VTOTAL) + : hp9845ct_state(mconfig , type , tag), + m_optional_chargen(*this , "optional_chargen") { } @@ -2274,26 +2288,6 @@ void hp9845c_state::plot(uint16_t x, uint16_t y, bool draw_erase) } } -void hp9845c_state::pattern_fill(uint16_t x0 , uint16_t y0 , uint16_t x1 , uint16_t y1) -{ - uint16_t x,y,xmax,ymax; - uint16_t pixel_mask, fill_mask; - - x = std::min(x0 , x1); - xmax = std::max(x0 , x1); - y = std::min(y0 , y1); - ymax = std::max(y0 , y1); - - for (;y <= ymax; y++) { - fill_mask = (m_area_fill[ m_gv_line_type_area_fill & 0xf ] << (y % 4) * 4) & 0xf000; - fill_mask |= (fill_mask >> 4) | (fill_mask >> 8) | (fill_mask >> 12); - for (;x <= xmax; x++) { - pixel_mask = (0x8000 >> (x % 16)); - plot(x , y , (pixel_mask & fill_mask) != 0); - } - } -} - void hp9845c_state::check_io_counter_restore(void) { if (m_gv_last_cmd != m_gv_cmd) { @@ -2540,7 +2534,7 @@ void hp9845c_state::advance_gv_fsm(bool ds , bool trigger) // fill area with pattern LOG(("area fill (%d,%d) -> (%d,%d) pattern=%04x\n", m_gv_last_xpt, m_gv_last_ypt, m_gv_xpt, m_gv_ypt, m_gv_line_type_area_fill)); - pattern_fill(m_gv_xpt , m_gv_ypt , m_gv_last_xpt , m_gv_last_ypt); + pattern_fill(m_gv_xpt , m_gv_ypt , m_gv_last_xpt , m_gv_last_ypt , m_gv_line_type_area_fill & 0xf); } m_gv_last_xpt = m_gv_xpt; m_gv_last_ypt = m_gv_ypt; @@ -2563,6 +2557,869 @@ void hp9845c_state::advance_gv_fsm(bool ds , bool trigger) update_graphic_bits(); } +void hp9845c_state::update_graphic_bits(void) +{ + bool gv_ready = m_gv_lp_int_en && m_gv_lp_status; + + if (m_gv_gr_en && !gv_ready) { + gv_ready = m_gv_fsm_state == GV_STAT_WAIT_DS_0 || + m_gv_fsm_state == GV_STAT_WAIT_TRIG_0 || + m_gv_fsm_state == GV_STAT_WAIT_DS_1 || + m_gv_fsm_state == GV_STAT_WAIT_DS_2 || + m_gv_fsm_state == GV_STAT_WAIT_TRIG_1; + } + + flg_w(GVIDEO_PA , gv_ready); + + bool irq = m_gv_int_en && !m_gv_dma_en && gv_ready; + + irq_w(GVIDEO_PA , irq); + + bool dmar = gv_ready && m_gv_dma_en; + + m_ppu->dmar_w(dmar); +} + +// *************** +// hp9845t_state +// *************** +class hp9845t_state : public hp9845ct_state +{ +public: + hp9845t_state(const machine_config &mconfig, device_type type, const char *tag); + + virtual void machine_start() override; + virtual void machine_reset() override; + + virtual DECLARE_READ16_MEMBER(graphic_r) override; + virtual DECLARE_WRITE16_MEMBER(graphic_w) override; + + TIMER_DEVICE_CALLBACK_MEMBER(scanline_timer); + +protected: + virtual void set_graphic_mode(bool graphic , bool alpha) override; + void video_render_buff(unsigned video_scanline , unsigned line_in_row, bool buff_idx); + void graphic_video_render(unsigned video_scanline); + virtual void plot(uint16_t x, uint16_t y, bool draw_erase) override; + void draw_arc(uint16_t x0, uint16_t y0, int xstart, int ystart, uint16_t radius, int quadrant, int& draw_counter); + void draw_full_arc(int x0 , int y0 , int dx , int dy , int draw_counter); + + virtual void advance_gv_fsm(bool ds , bool trigger) override; + virtual void update_graphic_bits(void) override; + + std::vector m_graphic_mem; + + bool m_gv_stat; + bool m_gv_increment_to_next_row; + + uint16_t m_gv_scan_start_x; + uint16_t m_gv_scan_start_y; + uint8_t m_gv_rb_control; + uint16_t m_gv_rb_counter; + uint16_t m_gv_rb_memory[ 256 ]; + uint16_t m_gv_arc[ 4 ]; + uint8_t m_gv_arc_parm; + bool m_back_arrow_cursor; + + static const uint8_t m_back_arrow_shape[]; +}; + +hp9845t_state::hp9845t_state(const machine_config &mconfig, device_type type, const char *tag) + : hp9845ct_state(mconfig , type , tag) +{ +} + +void hp9845t_state::machine_start() +{ + // Common part first + hp9845ct_state::machine_start(); + + m_graphic_mem.resize(GVIDEO_MEM_SIZE); + + // initialize palette + m_palette->set_pen_color(PEN_BLACK , 0x00, 0x00, 0x00); // black + m_palette->set_pen_color(PEN_GRAPHIC, 0x00, I_GR, 0x00); // graphics + m_palette->set_pen_color(PEN_ALPHA , 0x00, I_AL, 0x00); // alpha + m_palette->set_pen_color(PEN_CURSOR , 0x00, I_CU, 0x00); // graphics cursor + m_palette->set_pen_color(PEN_LP , 0x00, I_LP, 0x00); // lightpen cursor +} + +void hp9845t_state::machine_reset() +{ + // Common part first + hp9845ct_state::machine_reset(); + + m_gv_stat = false; + m_gv_increment_to_next_row = false; + m_gv_scan_start_x = 0; + m_gv_scan_start_y = 0; + m_gv_rb_control = 0; + m_gv_rb_counter = 0; + memset(m_gv_rb_memory, 0, sizeof(m_gv_rb_memory)); + m_back_arrow_cursor = false; + + set_video_mar(0); +} + +READ16_MEMBER(hp9845t_state::graphic_r) +{ + uint16_t res = 0; + + switch (offset) { + case 0: + // R4: data register + if (m_gv_lp_en) { + res = lp_r4_r(); + } else { + res = m_gv_data_r; + } + advance_gv_fsm(true , false); + break; + + case 1: + // R5: status register + if (m_gv_int_en) { + BIT_SET(res, 7); + } + if (m_gv_dma_en) { + BIT_SET(res, 6); + } + if (m_gv_lp_status && m_gv_lp_int_en) { + BIT_SET(res, 0); // Lightpen service request + } + // TODO: gsr/ + // TODO: fix sk status + if (m_gv_sk_status) { + BIT_SET(res, 1); // Softkey service request + m_gv_sk_status = false; + } + BIT_SET(res, 9); // ID + BIT_SET(res, 11); // ID + // TODO: fix grstat + if (m_gv_stat) { + BIT_SET(res, 13); // error indication + } + + update_graphic_bits(); + break; + + case 2: + // R6: data register with DMA TC + m_gv_dma_en = false; + if (m_gv_lp_en) { + res = lp_r4_r(); + } else { + res = m_gv_data_r; + } + advance_gv_fsm(true , false); + break; + + case 3: + // R7: not mapped + break; + } + + LOG(("rd gv R%u = %04x\n", 4 + offset , res)); + + return res; +} + +WRITE16_MEMBER(hp9845t_state::graphic_w) +{ + LOG(("wr gv R%u = %04x\n", 4 + offset , data)); + + switch (offset) { + case 0: + // R4: data register + m_gv_data_w = data; + advance_gv_fsm(true , false); + lp_r4_w(data); + break; + + case 1: + // R5: command register + m_gv_cmd = (uint8_t)(data & 0xf); + m_gv_dma_en = BIT(data , 6) != 0; + m_gv_int_en = BIT(data , 7) != 0; + m_gv_gr_en = BIT(data , 8); // enables graphics controller & vector generator command processing and IRQs + m_gv_sk_en = BIT(data , 9); // enables reads on R4 to return SK keycode, also enables SK IRQs + m_gv_opt_en = BIT(data , 11); // not really used + m_gv_dsa_en = BIT(data , 12); // for factory use only (function unknown) + m_gv_fsm_state = GV_STAT_RESET; // command/reset state machine + lp_r5_w(data); + advance_gv_fsm(false , false); + break; + + case 2: + // R6: data register with DMA TC + m_gv_dma_en = false; + m_gv_data_w = data; + lp_r4_w(data); + advance_gv_fsm(true , false); + break; + + case 3: + // R7: not mapped + break; + } +} + +TIMER_DEVICE_CALLBACK_MEMBER(hp9845t_state::scanline_timer) +{ + unsigned video_scanline = param; + + if (video_scanline >= VIDEO_780_VBEND && video_scanline < VIDEO_780_VBSTART) { + if (m_graphic_sel) { + graphic_video_render(video_scanline - VIDEO_780_VBEND); + } + unsigned row = (video_scanline - VIDEO_780_VBEND) / VIDEO_CHAR_HEIGHT; + unsigned line_in_row = (video_scanline - VIDEO_780_VBEND) - row * VIDEO_CHAR_HEIGHT; + + if (line_in_row == 0) { + // Start of new row, swap buffers + m_video_buff_idx = !m_video_buff_idx; + video_fill_buff(!m_video_buff_idx); + } + video_render_buff(video_scanline , line_in_row , m_video_buff_idx); + // Lightpen cursor + if (m_graphic_sel) { + render_lp_cursor(video_scanline - VIDEO_780_VBEND , PEN_LP); + } + } + lp_scanline_update(video_scanline - VIDEO_780_VBEND); +} + +void hp9845t_state::set_graphic_mode(bool graphic , bool alpha) +{ + m_back_arrow_cursor = graphic; // triggers back arrow cursor, 98780A uses video on/off command for enabling/disabling graphics + m_alpha_sel = alpha; +} + +void hp9845t_state::video_render_buff(unsigned video_scanline , unsigned line_in_row, bool buff_idx) +{ + if (!m_video_buff[ buff_idx ].full) { + m_video_blanked = true; + } + + const pen_t *pen = m_palette->pens(); + + if (m_video_blanked || !m_alpha_sel) { + // Blank scanline + for (unsigned i = 0; i < VIDEO_780_ALPHA_L_LIM; i++) { + m_bitmap.pix32(video_scanline , i) = pen[ PEN_BLACK ]; + } + if (!m_graphic_sel) { + for (unsigned i = VIDEO_780_ALPHA_L_LIM; i < VIDEO_780_ALPHA_R_LIM; i++) { + m_bitmap.pix32(video_scanline , i) = pen[ PEN_BLACK ]; + } + } + for (unsigned i = VIDEO_780_ALPHA_R_LIM; i < VIDEO_TOT_HPIXELS; i++) { + m_bitmap.pix32(video_scanline , i) = pen[ PEN_BLACK ]; + } + } else { + bool cursor_line = line_in_row == 12; + bool ul_line = line_in_row == 14; + unsigned video_frame = (unsigned)m_screen->frame_number(); + bool cursor_blink = BIT(video_frame , 3); + bool char_blink = BIT(video_frame , 4); + + for (unsigned i = 0; i < 80; i++) { + uint8_t attrs = m_video_buff[ buff_idx ].attrs[ i ]; + uint16_t pixels; + + if (!BIT(attrs , 2) || char_blink) { + if (ul_line && BIT(attrs , 3)) { + pixels = ~0; + } else { + // The 98780A uses two identical 4KB ROMs interlaced to keep up with the speed of + // the video circuit. Each of the 4K ROMs contains the full character set. + // The 98780A fills row 0 (space between characters) controlled by row 1 and 2 from + // the character ROM, thereby providing line drawing characters for continuous lines + uint8_t charcode = m_video_buff[ buff_idx ].chars[ i ]; + uint16_t chrgen_addr = ((uint16_t)(charcode ^ 0xff) << 4) | (line_in_row + 1); + pixels = (uint16_t)m_chargen[ chrgen_addr ] << 1; + if ((charcode & 0xe0) == 0xe0 && (pixels & 0x6) == 0x6) { + pixels |= 1; + } + } + } else { + pixels = 0; + } + + if (cursor_blink && BIT(attrs , 0)) { + if (m_back_arrow_cursor) { + // back arrow cursor (HP's hardware easter egg) + pixels |= m_back_arrow_shape[ line_in_row ]; + } else if (cursor_line) { + pixels = ~0; + } + } + + if (BIT(attrs , 1)) { + pixels = ~pixels; + } + + for (unsigned j = 0; j < 9; j++) { + bool pixel = (pixels & (1U << j)) != 0; + unsigned x = i * 9 + j; + + if (m_graphic_sel && x >= VIDEO_780_ALPHA_L_LIM && x < VIDEO_780_ALPHA_R_LIM) { + // alpha overlays graphics (non-dominating) + if (pixel) { + m_bitmap.pix32(video_scanline , x) = pen[ PEN_ALPHA ]; + } + } else { + // Graphics disabled or alpha-only zone + m_bitmap.pix32(video_scanline , x) = pen[ pixel ? PEN_ALPHA : PEN_BLACK ]; + } + } + } + } +} + +void hp9845t_state::graphic_video_render(unsigned video_scanline) +{ + // video_scanline is 0-based, i.e. the topmost visible line of graphic screen is 0 + const pen_t *pen = m_palette->pens(); + bool yc, yw, blink; + uint16_t word; + + yc = (video_scanline + 44) == m_gv_cursor_y; + + if (m_gv_cursor_fs) { + yw = true; + // Steady cursor + blink = true; + } else { + // 9 pixel + yw = (video_scanline + 44 > m_gv_cursor_y - 5) && + (video_scanline + 44 < m_gv_cursor_y + 5); + if (m_gv_cursor_gc) { + blink = true; + } else { + // Blinking cursor (frame freq. / 16) + blink = BIT(m_screen->frame_number() , 3) != 0; + } + } + + unsigned mem_idx = get_gv_mem_addr(m_gv_scan_start_x >> 4, video_scanline + m_gv_scan_start_y); + for (unsigned i = 0; i < GVIDEO_HPIXELS; i += 16) { + word = m_graphic_mem[ mem_idx ]; + mem_idx++; + // Is wraparound better? + if (mem_idx > GVIDEO_ADDR_MASK) return; + unsigned x = i; + for (uint16_t mask = 0x8000; mask != 0; mask >>= 1) { + bool xc = (x + 63) == m_gv_cursor_x; + bool xw = m_gv_cursor_fs || ((x + 67 >= m_gv_cursor_x) && (x + 59 <= m_gv_cursor_x)); + unsigned pixel; + + if (blink && ((xw && yc) || (yw && xc && m_gv_cursor_gc))) { + pixel = PEN_CURSOR; + } else { + // Normal pixel + if (m_gv_lp_fullbright) + pixel = word & mask ? PEN_LP : PEN_BLACK; + else + pixel = word & mask ? PEN_GRAPHIC : PEN_BLACK; + } + m_bitmap.pix32(video_scanline , VIDEO_780_ALPHA_L_LIM + x++) = pen[ pixel ]; + } + } +} + +void hp9845t_state::plot(uint16_t x, uint16_t y, bool draw_erase) +{ + uint16_t addr, pixel_mask; + bool do_draw; + + pixel_mask = 0x8000 >> (x & 0xf); + addr = get_gv_mem_addr(x >> 4 , y); + if (BIT(m_gv_rb_control, 1)) { + // save graphics memory to rubber band memory + if (m_graphic_mem[ addr ] & pixel_mask) + m_gv_rb_memory[m_gv_rb_counter/16] |= 0x1 << (m_gv_rb_counter % 16); // set + else + m_gv_rb_memory[m_gv_rb_counter/16] &= ~(0x1 << (m_gv_rb_counter % 16)); // clear + m_gv_rb_counter++; + if (m_gv_rb_counter > 4095) { + m_gv_stat = true; // we might prevent data corruption here, but the original hardware doesn't + m_gv_rb_counter = 0; + } + } else if (BIT(m_gv_rb_control, 0)) { + // restore graphics memory from rubber band memory + if (BIT(m_gv_rb_memory[m_gv_rb_counter / 16], m_gv_rb_counter % 16)) + m_graphic_mem[ addr ] |= pixel_mask; // set + else + m_graphic_mem[ addr ] &= ~pixel_mask; // clear + m_gv_rb_counter++; + if (m_gv_rb_counter > 4095) { + m_gv_stat = true; + m_gv_rb_counter = 0; + } + } else { + // draw/erase pixel + do_draw = m_gv_memory_control ? draw_erase : !draw_erase; + if (do_draw) + m_graphic_mem[ addr ] |= pixel_mask; + else + m_graphic_mem[ addr ] &= ~pixel_mask; + } +} + +void hp9845t_state::draw_arc(uint16_t x0, uint16_t y0, int xstart, int ystart, uint16_t radius, int quadrant, int& draw_counter) +{ + int i, x1, y1, d; + bool draw_erase; + bool do_plot = (xstart < 0) || (ystart < 0); + int save_x1[560]; + + /* quadrants: + * + * 1 | 0 + * ---+--- + * 2 | 3 + * + * Note: we are using Horn's algorithm here, however it is not 100% pixel + * accurate with the original vector generator + */ + + d = -radius; + x1 = radius; + y1 = 0; + i = 0; + while ((x1 > 0) && (draw_counter > 0)) { + // check for plot start + if (!do_plot) { + if ((quadrant % 2) == 0) { + if ((x1 <= xstart) && (y1 >= ystart)) do_plot = true; + } else { + if ((y1 >= xstart) && (x1 <= ystart)) do_plot = true; + } + } + + // draw pixels in quadrants + draw_erase = BIT(m_gv_line_type_mask, 15); + if (do_plot) { + switch (quadrant) { + case 0: + plot(x0 + x1, y0 - y1, draw_erase); // quadrant 0 + break; + case 1: + plot(x0 - y1, y0 - x1, draw_erase); // quadrant 1 + break; + case 2: + plot(x0 - x1, y0 + y1, draw_erase); // quadrant 2 + break; + case 3: + plot(x0 + y1, y0 + x1, draw_erase); // quadrant 3 + break; + } + } + + // update coordinates + if (x1 > y1) { + save_x1[i++] = x1; + d += 2 * y1 + 1; + y1++; + if (do_plot) draw_counter--; + if (d > 0) { + x1--; + if (do_plot) draw_counter--; + d -= 2 * x1; + } + if (x1 <= y1) draw_counter++; + } + else { + x1--; + y1 = save_x1[--i]; + if (do_plot) { + draw_counter--; + if (save_x1[i] != save_x1[i+1]) + draw_counter--; + } + } + update_line_pattern(); + } +} + +void hp9845t_state::draw_full_arc(int x0 , int y0 , int dx , int dy , int draw_counter) +{ + // radius + int radius = sqrt(dx * dx + dy * dy); + + LOG(("midpoint = (%d,%d) radius = %d ctrl = %d count = %d\n", x0, y0, radius, m_gv_memory_control, draw_counter)); + + /* quadrants: + * + * 1 | 0 + * ---+--- + * 2 | 3 + */ + + int quadrant = 0; + + // determine the start quadrant + if (dx > 0) + quadrant = (dy < 0) ? 1 : 2; + else + quadrant = (dy <= 0) ? 0 : 3; + + draw_arc(x0, y0, abs(dx), abs(dy), radius, quadrant, draw_counter); + while (draw_counter > 0) { + quadrant++; + if (quadrant > 3) { + quadrant = 0; + } + draw_arc(x0, y0, -1, -1, radius, quadrant, draw_counter); + } +} + +void hp9845t_state::advance_gv_fsm(bool ds , bool trigger) +{ + if (!m_gv_gr_en) { + return; + } + + bool get_out = false; + + attotime time_mem_av; + + do { + switch (m_gv_fsm_state) { + case GV_STAT_WAIT_DS_0: + // inital state (same as GV_STAT_RESET), command received + if (m_gv_cmd == 0x9) { + // read words command + if (m_gv_last_cmd != m_gv_cmd) { + m_gv_io_counter = get_gv_mem_addr(m_gv_word_x_position , m_gv_word_y_position); + } + LOG(("read words, last = %x\n", m_gv_last_cmd)); + m_gv_fsm_state = GV_STAT_WAIT_MEM_0; // -> read stream + m_gv_last_cmd = m_gv_cmd; + } else if (m_gv_cmd == 0xd) { + // fast clear/set command + m_gv_fsm_state = GV_STAT_WAIT_MEM_2; + m_gv_last_cmd = m_gv_cmd; + } else if (ds) { + if (m_gv_cmd == 0x8) { + // write words command + if (m_gv_last_cmd != m_gv_cmd) { + m_gv_io_counter = get_gv_mem_addr(m_gv_word_x_position , m_gv_word_y_position); + } + LOG(("write words\n")); + m_gv_fsm_state = GV_STAT_WAIT_TRIG_1; // -> write stream + } else { + // any other command + m_gv_fsm_state = GV_STAT_WAIT_TRIG_0; // -> wait for trigger + } + m_gv_last_cmd = m_gv_cmd; + } else { + get_out = true; + } + break; + + case GV_STAT_WAIT_TRIG_0: + // process data on R4 or R6 + switch (m_gv_cmd) { + case 0x1: // load end points + m_gv_ypt = m_gv_data_w & 0x3ff; + LOG(("load end points y = %d\n", m_gv_ypt)); + break; + case 0x3: // load arc + m_gv_arc_parm = 0; + m_gv_arc[ m_gv_arc_parm ] = m_gv_data_w; + LOG(("load arc parm%d = %04x\n", m_gv_arc_parm, m_gv_arc[m_gv_arc_parm])); + m_gv_arc_parm++; + break; + case 0x5: // load scan + m_gv_scan_start_x = m_gv_data_w & 0x3ff; // 0..559 + LOG(("load scan x = %d\n", m_gv_scan_start_x)); + break; + case 0x6: // set line type/area fill + m_gv_line_type_area_fill = m_gv_data_w & 0x1ff; + if (BIT(m_gv_line_type_area_fill, 4)) { + m_gv_line_type_mask = m_line_type[ m_gv_line_type_area_fill & 0x7 ]; + m_gv_repeat_count = 0; + } + LOG(("set line type = %04x\n", m_gv_line_type_area_fill)); + break; + case 0x7: // load X/Y I/O address + m_gv_word_y_position = m_gv_data_w & 0x1ff; // 0..454 + LOG(("load X/Y I/O adress y = %04x\n", m_gv_word_y_position)); + break; + case 0xa: // load memory control + // A single bit is saved (InvBit) + m_gv_memory_control = (m_gv_data_w & 0x9) == 9 || (m_gv_data_w & 0x12) == 0x12 || (m_gv_data_w & 0x24) == 0x24; + LOG(("load memory control = %04x\n", m_gv_memory_control)); + break; + case 0xb: // video on/off - enable graphics video output (1=on 2=off) + m_graphic_sel = BIT(m_gv_data_w, 0); + LOG(("video on/off parm = %d\n", m_gv_data_w & 0x3)); + break; + case 0xc: // load color mask (no effect, just for compatibility with 9845c), takes a single word as parameter + break; + case 0xe: // Y cursor position + m_gv_cursor_fs = (m_gv_data_w & 0x3) == 0; + m_gv_cursor_gc = ((m_gv_data_w & 0x3) == 1) || m_gv_cursor_fs; + m_gv_cursor_y = 559 - (m_gv_data_w >> 7); + if (m_gv_cursor_fs) m_gv_cursor_y -= 4; + LOG(("Y cursor position = %d, fs = %d, gc = %d\n", m_gv_cursor_y, m_gv_cursor_fs, m_gv_cursor_gc)); + break; + case 0xf: // X cursor position + m_gv_cursor_x = ((m_gv_data_w >> 6) & 0x3ff) - 121; + LOG(("X cursor position = %d\n", m_gv_cursor_x)); + break; + default: + LOG(("unknown 98780A command = %d, parm = 0x%04x\n", m_gv_cmd, m_gv_data_w)); + } + if ((m_gv_cmd == 0x1) || (m_gv_cmd == 0x3) || (m_gv_cmd == 0x5) || (m_gv_cmd == 0x7)) { + m_gv_fsm_state = GV_STAT_WAIT_DS_2; // -> get second data word + } else { + get_out = true; + m_gv_fsm_state = GV_STAT_WAIT_DS_0; // -> done + } + break; + + case GV_STAT_WAIT_MEM_0: + // process data during read transfer + time_mem_av = time_to_gv_mem_availability(); + if (time_mem_av.is_zero()) { + // Read a word from graphic memory + m_gv_data_r = m_graphic_mem[ m_gv_io_counter ]; + LOG(("read words @%04x = %04x\n" , m_gv_io_counter , m_gv_data_r)); + m_gv_io_counter = (m_gv_io_counter + 1) & GVIDEO_ADDR_MASK; + m_gv_fsm_state = GV_STAT_WAIT_DS_1; // -> proceed with read stream + } else { + m_gv_timer->adjust(time_mem_av); + get_out = true; + } + break; + + case GV_STAT_WAIT_DS_1: + // wait for data word to be read + if (ds) { + // -- next word + m_gv_fsm_state = GV_STAT_WAIT_MEM_0; // -> process data word + } else { + // -- done + get_out = true; + } + break; + + case GV_STAT_WAIT_DS_2: + // wait for data word to be written + if (ds) { + // -- next word + m_gv_fsm_state = GV_STAT_WAIT_TRIG_1; // -> process data word + } else { + // done + get_out = true; + } + break; + + case GV_STAT_WAIT_TRIG_1: + // process multi-word parameters & data during write transfer + switch (m_gv_cmd) { + case 0x1: + // load endpoints command + m_gv_xpt = m_gv_data_w & 0x3ff; + // RB control is actually set whenever a data word is written into R4/R6 register, not just here + m_gv_rb_control = (m_gv_data_w >> 13) & 0x7; + if (BIT(m_gv_rb_control, 2)) { + m_gv_rb_counter = 0; + m_gv_stat = false; + } + if (BIT(m_gv_data_w, 11)) { + // draw vector + LOG(("load end points x = %d, rb = %d (draw)\n", m_gv_xpt, m_gv_rb_control)); + m_gv_fsm_state = GV_STAT_WAIT_MEM_2; // -> proceed with draw vector + } else { + LOG(("load end points x = %d, rb = %d (move)\n", m_gv_xpt, m_gv_rb_control)); + m_gv_last_xpt = m_gv_xpt; + m_gv_last_ypt = m_gv_ypt; + m_gv_fsm_state = GV_STAT_WAIT_DS_0; // -> proceed with next word pair + } + break; + + case 0x3: + // load arc + m_gv_arc[ m_gv_arc_parm ] = m_gv_data_w; + LOG(("load arc parm%d = %04x\n", m_gv_arc_parm, m_gv_arc[m_gv_arc_parm])); + m_gv_arc_parm++; + if (m_gv_arc_parm < 4) { + m_gv_fsm_state = GV_STAT_WAIT_DS_2; // -> proceed with next word + } else { + m_gv_fsm_state = GV_STAT_WAIT_MEM_2; // -> proceed with draw vector + } + break; + + case 0x5: + // load scan + m_gv_scan_start_y = m_gv_data_w & 0x3ff; // 0..454 + LOG(("load scan y = %d\n", m_gv_scan_start_y)); + m_gv_fsm_state = GV_STAT_WAIT_DS_0; + break; + + case 0x7: + // load X/Y I/O address + m_gv_word_x_position = (m_gv_data_w & 0x3f0) >> 4; // 0..34 + m_gv_increment_to_next_row = BIT(m_gv_data_w, 11); + m_gv_io_counter = get_gv_mem_addr(m_gv_word_x_position , m_gv_word_y_position); + LOG(("load X/Y I/O adress x = %04x increment = %d\n", m_gv_word_x_position, m_gv_increment_to_next_row)); + m_gv_fsm_state = GV_STAT_WAIT_DS_0; + break; + + case 0x8: + // write words command + m_gv_fsm_state = GV_STAT_WAIT_MEM_1; // -> proceed with next word + break; + } + break; + + case GV_STAT_WAIT_MEM_1: + // -- transfer from bus to graphics memory to bus within write transfer + time_mem_av = time_to_gv_mem_availability(); + if (time_mem_av.is_zero()) { + // Write a full word to graphic memory + LOG(("write words @%04x = %04x\n" , m_gv_io_counter , m_gv_data_w)); + m_graphic_mem[ m_gv_io_counter ] = m_gv_data_w; + if (!m_gv_increment_to_next_row || (m_gv_word_x_position < 34)) { + m_gv_io_counter = (m_gv_io_counter + 1) & GVIDEO_ADDR_MASK; + } + m_gv_fsm_state = GV_STAT_WAIT_DS_2; // -> proceed with write stream + } else { + m_gv_timer->adjust(time_mem_av); + get_out = true; + } + break; + + case GV_STAT_WAIT_MEM_2: + // vector generator + time_mem_av = time_to_gv_mem_availability(); + if (time_mem_av.is_zero()) { + if (m_gv_cmd == 0xd) { + // fast clear/set command + if (m_gv_memory_control) { + LOG(("fast clear/set (set)\n")); + for (auto& el : m_graphic_mem) { + el = 0xffff; + } + } else { + LOG(("fast clear/set (clear)\n")); + for (auto& el : m_graphic_mem) { + el = 0; + } + } + } else { + if (m_gv_cmd == 0x3) { + // draw arc/circle + // drawing is performed counter-clockwise by using Horn's algorithm + // m_gv_arc[0] is the delta last load endpoint y coordinate minus the midpoint y coordinate + // m_gv_arc[1] is the delta last load endpoint x coordinate minus the midpoint x coordinate + // m_gv_arc[2] is the (probably) the start count (?), actually ignored + // m_gv_arc[3] is the total horizontal + vertical count for the 4 quadrants counter-clockwise, starting at the last load endpoint (equals 4 times radius for full circles) + LOG(("arc draw\n")); + + // midpoint + int dx = BIT(m_gv_arc[ 1 ] , 15) ? (int)m_gv_arc[ 1 ] - 65536 : m_gv_arc[ 1 ] & 0x7ff; + int dy = BIT(m_gv_arc[ 0 ] , 15) ? (int)m_gv_arc[ 0 ] - 65536 : m_gv_arc[ 0 ]; + int x0 = m_gv_xpt + dx; + int y0 = m_gv_ypt - dy; + + draw_full_arc(x0 , y0 , dx , dy , m_gv_arc[ 3 ]); + } else if (BIT (m_gv_line_type_area_fill, 4)) { + unsigned x0; + unsigned x1; + unsigned y0; + unsigned y1; + + LOG(("line draw (%d,%d)->(%d,%d)\n", m_gv_last_xpt, m_gv_last_ypt, m_gv_xpt, m_gv_ypt)); + + // vector generator uses normalization + if (m_gv_xpt > m_gv_last_xpt) { + x0 = m_gv_last_xpt; + y0 = m_gv_last_ypt; + x1 = m_gv_xpt; + y1 = m_gv_ypt; + } else { + x0 = m_gv_xpt; + y0 = m_gv_ypt; + x1 = m_gv_last_xpt; + y1 = m_gv_last_ypt; + } + draw_line(x0 , y0 , x1 , y1); + } else { + // fill area with pattern + LOG(("area fill (%d,%d) -> (%d,%d) pattern=%04x\n", m_gv_last_xpt, m_gv_last_ypt, m_gv_xpt, m_gv_ypt, m_gv_line_type_area_fill)); + + pattern_fill(m_gv_xpt , m_gv_ypt , m_gv_last_xpt , m_gv_last_ypt , 15 - (m_gv_line_type_area_fill & 0xf)); + } + m_gv_last_xpt = m_gv_xpt; + m_gv_last_ypt = m_gv_ypt; + } + m_gv_fsm_state = GV_STAT_WAIT_DS_0; + } else { + m_gv_timer->adjust(time_mem_av); + } + get_out = true; + break; + + default: + logerror("Invalid state reached %d\n" , m_gv_fsm_state); + m_gv_fsm_state = GV_STAT_RESET; + } + + ds = false; + } while (!get_out); + + update_graphic_bits(); +} + +void hp9845t_state::update_graphic_bits(void) +{ + bool gv_ready = m_gv_lp_int_en && m_gv_lp_status; + + if (m_gv_gr_en && !gv_ready) { + gv_ready = m_gv_fsm_state == GV_STAT_WAIT_DS_0 || + m_gv_fsm_state == GV_STAT_WAIT_DS_1 || + m_gv_fsm_state == GV_STAT_WAIT_DS_2; + } + +#ifdef HP98780A_REAL_HW + // In 98780 real hw, the FLG signal is apparently set to true + // whenever the LP is selected, regardless of its interrupt + // request status. + flg_w(GVIDEO_PA , gv_ready || m_gv_lp_int_en); +#else + // In Duell's schematics, the FLG signal follows the + // LP interrupt request + flg_w(GVIDEO_PA , gv_ready); +#endif + + bool irq = m_gv_int_en && !m_gv_dma_en && gv_ready; + +#if 0 + // DEBUG DEBUG DEBUG + static bool last_irq = false; + if (!last_irq && irq) { + logerror("GV IRQ %d %d %d\n" , gv_ready , m_gv_lp_int_en , m_gv_lp_status); + } + last_irq = irq; +#endif + + irq_w(GVIDEO_PA , irq); + + bool dmar = gv_ready && m_gv_dma_en; + + m_ppu->dmar_w(dmar); +} + +const uint8_t hp9845t_state::m_back_arrow_shape[] = { + 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xfc, + 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00 +}; + static MACHINE_CONFIG_START( hp9845a, hp9845_state ) //MCFG_CPU_ADD("lpu", HP_5061_3010, XTAL_11_4MHz) //MCFG_CPU_ADD("ppu", HP_5061_3011, XTAL_11_4MHz) @@ -2594,31 +3451,31 @@ static MACHINE_CONFIG_START( hp9835a, hp9845_state ) MACHINE_CONFIG_END /* - Global memory map in blocks of 32 kwords / 64 kbytes each: + Global memory map in blocks of 32 kwords / 64 kbytes each: - block 0: 0x000000 - 0x007fff (LPU RAM) - block 1: 0x008000 - 0x00ffff (PPU RAM, only 0x00c000 - 0x00ffff used) - block 2: 0x010000 - 0x017fff (unused) - block 3: 0x018000 - 0x01ffff (LPU system ROM) - block 4: 0x020000 - 0x027fff (LPU RAM) - block 5: 0x028000 - 0x02ffff (PPU system ROM) - block 6: 0x030000 - 0x037fff (LPU RAM) - block 7: 0x038000 - 0x03ffff (LPU option ROM) - block 10: 0x040000 - 0x047fff (LPU RAM) - block 11: 0x048000 - 0x04ffff (PPU option ROM) - block 12: 0x050000 - 0x057fff (LPU RAM) - block 13: 0x058000 - 0x05ffff (LPU option ROM) - block 14: 0x060000 - 0x067fff (LPU RAM) - block 15: 0x068000 - 0x06ffff (PPU option ROM) - block 16: 0x070000 - 0x077fff (LPU RAM) - block 17: 0x078000 - 0x07ffff (unused) + block 0: 0x000000 - 0x007fff (LPU RAM) + block 1: 0x008000 - 0x00ffff (PPU RAM, only 0x00c000 - 0x00ffff used) + block 2: 0x010000 - 0x017fff (unused) + block 3: 0x018000 - 0x01ffff (LPU system ROM) + block 4: 0x020000 - 0x027fff (LPU RAM) + block 5: 0x028000 - 0x02ffff (PPU system ROM) + block 6: 0x030000 - 0x037fff (LPU RAM) + block 7: 0x038000 - 0x03ffff (LPU option ROM) + block 10: 0x040000 - 0x047fff (LPU RAM) + block 11: 0x048000 - 0x04ffff (PPU option ROM) + block 12: 0x050000 - 0x057fff (LPU RAM) + block 13: 0x058000 - 0x05ffff (LPU option ROM) + block 14: 0x060000 - 0x067fff (LPU RAM) + block 15: 0x068000 - 0x06ffff (PPU option ROM) + block 16: 0x070000 - 0x077fff (LPU RAM) + block 17: 0x078000 - 0x07ffff (unused) - notes: - - all block numbers are octal - - blocks 20 to 76 are reserved for 512 kbyte RAM boards (p/n 09845-66590) - - block 45 is reserved for the Test ROM - - memory addresses are continuous (for convenience, the mapping below uses block numbers as - address part above 0xffff, so there are gaps between 0x8000 and 0xffff which are masked out). + notes: + - all block numbers are octal + - blocks 20 to 76 are reserved for 512 kbyte RAM boards (p/n 09845-66590) + - block 45 is reserved for the Test ROM + - memory addresses are continuous (for convenience, the mapping below uses block numbers as + address part above 0xffff, so there are gaps between 0x8000 and 0xffff which are masked out). - all LPU RAM is dynamically mapped at machine start according to -ramsize option */ @@ -2755,7 +3612,22 @@ static MACHINE_CONFIG_START(hp9845c, hp9845c_state) MACHINE_CONFIG_END -ROM_START( hp9845a ) +static MACHINE_CONFIG_START(hp9845t, hp9845t_state) + MCFG_FRAGMENT_ADD(hp9845_base) + // video hardware + MCFG_SCREEN_MODIFY("screen") + MCFG_SCREEN_UPDATE_DRIVER(hp9845t_state, screen_update) + MCFG_SCREEN_VBLANK_CALLBACK(WRITELINE(hp9845t_state, vblank_w)) + MCFG_SCREEN_COLOR(rgb_t::green()) + MCFG_SCREEN_RAW_PARAMS(VIDEO_780_PIXEL_CLOCK , VIDEO_780_HTOTAL , VIDEO_780_HBEND , VIDEO_780_HBSTART , VIDEO_780_VTOTAL , VIDEO_780_VBEND , VIDEO_780_VBSTART) + MCFG_PALETTE_ADD("palette", 5) + MCFG_TIMER_DRIVER_ADD_SCANLINE("scantimer", hp9845t_state, scanline_timer, "screen", 0, 1) + + MCFG_SOFTWARE_LIST_ADD("optrom_list", "hp9845b_rom") + +MACHINE_CONFIG_END + + ROM_START( hp9845a ) ROM_REGION( 0200000, "lpu", ROMREGION_16BIT | ROMREGION_BE ) ROM_LOAD( "09845-65544-65547-03-system_lpu.bin", 0000000, 0200000, CRC(47beb87f) SHA1(456caefacafcf19435e1e7e68b1c1e4010841664) ) @@ -2855,8 +3727,6 @@ ROM_START( hp9845b ) #endif ROM_END -#define rom_hp9845t rom_hp9845b - ROM_START( hp9845c ) ROM_REGION(0x800 , "chargen" , 0) ROM_LOAD("chrgen.bin" , 0 , 0x800 , CRC(fe9e844f) SHA1(0c45ae00766ceba94a19bd5e154bd6d23e208cca)) @@ -2871,10 +3741,23 @@ ROM_START( hp9845c ) ROM_LOAD("9845-PPU-Color-Enhanced-Graphics.bin", 0, 0x10000, CRC(96e11edc) SHA1(3f1da50edb35dfc57ec2ecfd816a8c8230e110bd)) ROM_END +ROM_START( hp9845t ) + //ROM_REGION(0x1000 , "chargen" , 0) + //ROM_LOAD("1818-1395-sh.bin" , 0 , 0x1000 , CRC(361e5eca) SHA1(62c81e133bd1ce19212b1da57a05074abccae247)) + ROM_REGION(0x1000 , "chargen" , 0) + ROM_LOAD("1818-1395-s2.bin" , 0 , 0x1000 , CRC(7b555edf) SHA1(3b08e094635ef02aef9a2e37b049c61bcf1ec037)) + + ROM_REGION(0x10000, "lpu", ROMREGION_16BIT | ROMREGION_BE) + ROM_LOAD("9845-LPU-Standard-Processor.bin", 0, 0x10000, CRC(dc266c1b) SHA1(1cf3267f13872fbbfc035b70f8b4ec6b5923f182)) + + ROM_REGION(0x10000, "ppu", ROMREGION_16BIT | ROMREGION_BE) + ROM_LOAD("9845-PPU-Color-Enhanced-Graphics.bin", 0, 0x10000, CRC(96e11edc) SHA1(3f1da50edb35dfc57ec2ecfd816a8c8230e110bd)) +ROM_END + COMP( 1978, hp9845a, 0, 0, hp9845a, hp9845, driver_device, 0, "Hewlett-Packard", "9845A", MACHINE_IS_SKELETON | MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) COMP( 1978, hp9845s, hp9845a, 0, hp9845a, hp9845, driver_device, 0, "Hewlett-Packard", "9845S", MACHINE_IS_SKELETON | MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) COMP( 1979, hp9835a, 0, 0, hp9835a, hp9845, driver_device, 0, "Hewlett-Packard", "9835A", MACHINE_IS_SKELETON | MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) COMP( 1979, hp9835b, hp9835a, 0, hp9835a, hp9845, driver_device, 0, "Hewlett-Packard", "9835B", MACHINE_IS_SKELETON | MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) -COMP( 1980, hp9845b, 0, 0, hp9845b, hp9845_base,driver_device, 0, "Hewlett-Packard", "9845B", 0 ) -COMP( 1980, hp9845t, hp9845b, 0, hp9845b, hp9845_base,driver_device, 0, "Hewlett-Packard", "9845T", MACHINE_IS_SKELETON | MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) +COMP( 1980, hp9845b, 0, 0, hp9845b, hp9845_base,driver_device, 0, "Hewlett-Packard", "9845B", 0 ) +COMP( 1980, hp9845t, 0, 0, hp9845t, hp9845ct,driver_device, 0, "Hewlett-Packard", "9845T", 0 ) COMP( 1981, hp9845c, 0, 0, hp9845c, hp9845ct,driver_device, 0, "Hewlett-Packard", "9845C", 0 ) diff --git a/src/mame/includes/hp9845.h b/src/mame/includes/hp9845.h index d54496d537c..0e31e0f3952 100644 --- a/src/mame/includes/hp9845.h +++ b/src/mame/includes/hp9845.h @@ -76,9 +76,6 @@ protected: // Character generator required_region_ptr m_chargen; - // Optional character generator - required_region_ptr m_optional_chargen; - // Text mode video I/F typedef struct { uint8_t chars[ 80 ];