1 // license:BSD-3-Clause 2 // copyright-holders:Wilbert Pol,Nigel Barnes 3 /********************************************************************** 4 5 Motorola MC6845 and compatible CRT controller emulation 6 7 *********************************************************************** 8 ____ ____ 9 GND 1 |* \__/ | 40 VS 10 _RESET 2 | | 39 HS 11 LPSTB 3 | | 38 RA0 12 MA0 4 | | 37 RA1 13 MA1 5 | | 36 RA2 14 MA2 6 | | 35 RA3 15 MA3 7 | | 34 RA4 16 MA4 8 | | 33 D0 17 MA5 9 | | 32 D1 18 MA6 10 | | 31 D2 19 MA7 11 | MC6845 | 30 D3 20 MA8 12 | | 29 D4 21 MA9 13 | | 28 D5 22 MA10 14 | | 27 D6 23 MA11 15 | | 26 D7 24 MA12 16 | | 25 _CS 25 MA13 17 | | 24 RS 26 DE 18 | | 23 E 27 CURSOR 19 | | 22 R/_W 28 Vcc 20 |____________| 21 CLK 29 30 **********************************************************************/ 31 32 #ifndef MAME_VIDEO_MC6845_H 33 #define MAME_VIDEO_MC6845_H 34 35 #pragma once 36 37 38 /* callback definitions */ 39 #define MC6845_RECONFIGURE(name) void name(int width, int height, const rectangle &visarea, attoseconds_t frame_period) 40 41 #define MC6845_BEGIN_UPDATE(name) void name(bitmap_rgb32 &bitmap, const rectangle &cliprect) 42 43 #define MC6845_UPDATE_ROW(name) void name(bitmap_rgb32 &bitmap, const rectangle &cliprect, uint16_t ma, uint8_t ra, \ 44 uint16_t y, uint8_t x_count, int8_t cursor_x, int de, int hbp, int vbp) 45 46 #define MC6845_END_UPDATE(name) void name(bitmap_rgb32 &bitmap, const rectangle &cliprect) 47 48 #define MC6845_ON_UPDATE_ADDR_CHANGED(name) void name(int address, int strobe) 49 50 51 class mc6845_device : public device_t, 52 public device_video_interface 53 { 54 public: 55 typedef device_delegate<void (int width, int height, const rectangle &visarea, attoseconds_t frame_period)> reconfigure_delegate; 56 typedef device_delegate<void (bitmap_rgb32 &bitmap, const rectangle &cliprect)> begin_update_delegate; 57 typedef device_delegate<void (bitmap_rgb32 &bitmap, const rectangle &cliprect, uint16_t ma, uint8_t ra, 58 uint16_t y, uint8_t x_count, int8_t cursor_x, int de, int hbp, int vbp)> update_row_delegate; 59 typedef device_delegate<void (bitmap_rgb32 &bitmap, const rectangle &cliprect)> end_update_delegate; 60 typedef device_delegate<void (int address, int strobe)> on_update_addr_changed_delegate; 61 62 // construction/destruction 63 mc6845_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); 64 set_show_border_area(bool show)65 void set_show_border_area(bool show) { m_show_border_area = show; } set_visarea_adjust(int min_x,int max_x,int min_y,int max_y)66 void set_visarea_adjust(int min_x, int max_x, int min_y, int max_y) 67 { 68 m_visarea_adjust_min_x = min_x; 69 m_visarea_adjust_max_x = max_x; 70 m_visarea_adjust_min_y = min_y; 71 m_visarea_adjust_max_y = max_y; 72 } set_char_width(int pixels)73 void set_char_width(int pixels) { m_hpixels_per_column = pixels; } 74 set_reconfigure_callback(T &&...args)75 template <typename... T> void set_reconfigure_callback(T &&... args) { m_reconfigure_cb.set(std::forward<T>(args)...); } set_begin_update_callback(T &&...args)76 template <typename... T> void set_begin_update_callback(T &&... args) { m_begin_update_cb.set(std::forward<T>(args)...); } set_update_row_callback(T &&...args)77 template <typename... T> void set_update_row_callback(T &&... args) { m_update_row_cb.set(std::forward<T>(args)...); } set_end_update_callback(T &&...args)78 template <typename... T> void set_end_update_callback(T &&... args) { m_end_update_cb.set(std::forward<T>(args)...); } set_on_update_addr_change_callback(T &&...args)79 template <typename... T> void set_on_update_addr_change_callback(T &&... args) { m_on_update_addr_changed_cb.set(std::forward<T>(args)...); } 80 out_de_callback()81 auto out_de_callback() { return m_out_de_cb.bind(); } out_cur_callback()82 auto out_cur_callback() { return m_out_cur_cb.bind(); } out_hsync_callback()83 auto out_hsync_callback() { return m_out_hsync_cb.bind(); } out_vsync_callback()84 auto out_vsync_callback() { return m_out_vsync_cb.bind(); } 85 86 /* select one of the registers for reading or writing */ 87 void address_w(uint8_t data); 88 89 /* read from the status register */ 90 uint8_t status_r(); 91 92 /* read from the currently selected register */ 93 uint8_t register_r(); 94 95 /* write to the currently selected register */ 96 void register_w(uint8_t data); 97 98 // read display enable line state 99 DECLARE_READ_LINE_MEMBER( de_r ); 100 101 // read cursor line state 102 DECLARE_READ_LINE_MEMBER( cursor_r ); 103 104 // read horizontal sync line state 105 DECLARE_READ_LINE_MEMBER( hsync_r ); 106 107 // read vertical sync line state 108 DECLARE_READ_LINE_MEMBER( vsync_r ); 109 110 /* return the current value on the MA0-MA13 pins */ 111 uint16_t get_ma(); 112 113 /* return the current value on the RA0-RA4 pins */ 114 uint8_t get_ra(); 115 116 /* simulates the LO->HI clocking of the light pen pin (pin 3) */ 117 void assert_light_pen_input(); 118 119 /* set number of pixels per video memory address */ 120 void set_hpixels_per_column(int hpixels_per_column); 121 122 /* updates the screen -- this will call begin_update(), 123 followed by update_row() repeatedly and after all row 124 updating is complete, end_update() */ 125 uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); 126 127 protected: 128 mc6845_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); 129 130 // device-level overrides 131 virtual void device_start() override; 132 virtual void device_reset() override; 133 virtual void device_post_load() override; 134 virtual void device_clock_changed() override; 135 virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; 136 cclks_to_attotime(uint64_t clocks)137 attotime cclks_to_attotime(uint64_t clocks) const { return clocks_to_attotime(clocks * m_clk_scale); } attotime_to_cclks(const attotime & duration)138 uint64_t attotime_to_cclks(const attotime &duration) const { return attotime_to_clocks(duration) / m_clk_scale; } 139 140 bool m_supports_disp_start_addr_r; 141 bool m_supports_vert_sync_width; 142 bool m_supports_status_reg_d5; 143 bool m_supports_status_reg_d6; 144 bool m_supports_status_reg_d7; 145 bool m_supports_transparent; 146 147 /* register file */ 148 uint8_t m_horiz_char_total; /* 0x00 */ 149 uint8_t m_horiz_disp; /* 0x01 */ 150 uint8_t m_horiz_sync_pos; /* 0x02 */ 151 uint8_t m_sync_width; /* 0x03 */ 152 uint8_t m_vert_char_total; /* 0x04 */ 153 uint8_t m_vert_total_adj; /* 0x05 */ 154 uint8_t m_vert_disp; /* 0x06 */ 155 uint8_t m_vert_sync_pos; /* 0x07 */ 156 uint8_t m_mode_control; /* 0x08 */ 157 uint8_t m_max_ras_addr; /* 0x09 */ 158 uint8_t m_cursor_start_ras; /* 0x0a */ 159 uint8_t m_cursor_end_ras; /* 0x0b */ 160 uint16_t m_disp_start_addr; /* 0x0c/0x0d */ 161 uint16_t m_cursor_addr; /* 0x0e/0x0f */ 162 uint16_t m_light_pen_addr; /* 0x10/0x11 */ 163 uint16_t m_update_addr; /* 0x12/0x13 */ 164 165 /* other internal state */ 166 uint8_t m_register_address_latch; 167 bool m_cursor_state; 168 uint8_t m_cursor_blink_count; 169 bool m_update_ready_bit; 170 /* output signals */ 171 int m_cur; 172 int m_hsync; 173 int m_vsync; 174 int m_de; 175 176 /* internal counters */ 177 uint8_t m_character_counter; /* Not used yet */ 178 uint8_t m_hsync_width_counter; /* Not used yet */ 179 uint8_t m_line_counter; 180 uint8_t m_raster_counter; 181 uint8_t m_adjust_counter; 182 uint8_t m_vsync_width_counter; 183 184 bool m_line_enable_ff; /* Internal flip flop which is set when the line_counter is reset and reset when vert_disp is reached */ 185 uint8_t m_vsync_ff; 186 uint8_t m_adjust_active; 187 uint16_t m_line_address; 188 int16_t m_cursor_x; 189 190 /* timers */ 191 static const device_timer_id TIMER_LINE = 0; 192 static const device_timer_id TIMER_DE_OFF = 1; 193 static const device_timer_id TIMER_CUR_ON = 2; 194 static const device_timer_id TIMER_CUR_OFF = 3; 195 static const device_timer_id TIMER_HSYNC_ON = 4; 196 static const device_timer_id TIMER_HSYNC_OFF = 5; 197 static const device_timer_id TIMER_LIGHT_PEN_LATCH = 6; 198 static const device_timer_id TIMER_UPD_ADR = 7; 199 static const device_timer_id TIMER_UPD_TRANS = 8; 200 201 emu_timer *m_line_timer; 202 emu_timer *m_de_off_timer; 203 emu_timer *m_cur_on_timer; 204 emu_timer *m_cur_off_timer; 205 emu_timer *m_hsync_on_timer; 206 emu_timer *m_hsync_off_timer; 207 emu_timer *m_light_pen_latch_timer; 208 emu_timer *m_upd_adr_timer; 209 emu_timer *m_upd_trans_timer; 210 211 /* computed values - do NOT state save these! */ 212 /* These computed are used to define the screen parameters for a driver */ 213 uint16_t m_horiz_pix_total; 214 uint16_t m_vert_pix_total; 215 uint16_t m_max_visible_x; 216 uint16_t m_max_visible_y; 217 uint16_t m_hsync_on_pos; 218 uint16_t m_hsync_off_pos; 219 uint16_t m_vsync_on_pos; 220 uint16_t m_vsync_off_pos; 221 bool m_has_valid_parameters; 222 bool m_display_disabled_msg_shown; 223 224 uint16_t m_current_disp_addr; /* the display address currently drawn (used only in mc6845_update) */ 225 226 bool m_light_pen_latched; 227 attotime m_upd_time; 228 229 void update_upd_adr_timer(); 230 void call_on_update_address(int strobe); 231 void transparent_update(); 232 void recompute_parameters(bool postload); 233 void update_counters(); 234 void set_de(int state); 235 void set_hsync(int state); 236 void set_vsync(int state); 237 void set_cur(int state); 238 bool match_line(); 239 virtual bool check_cursor_visible(uint16_t ra, uint16_t line_addr); 240 void handle_line_timer(); 241 virtual void update_cursor_state(); 242 virtual uint8_t draw_scanline(int y, bitmap_rgb32 &bitmap, const rectangle &cliprect); 243 244 /************************ 245 interface CRTC - driver 246 ************************/ 247 248 bool m_show_border_area; /* visible screen area (false) active display (true) active display + blanking */ 249 int m_noninterlace_adjust; /* adjust max ras in non-interlace mode */ 250 int m_interlace_adjust; /* adjust max ras in interlace mode */ 251 252 uint32_t m_clk_scale; 253 254 /* visible screen area adjustment */ 255 int m_visarea_adjust_min_x; 256 int m_visarea_adjust_max_x; 257 int m_visarea_adjust_min_y; 258 int m_visarea_adjust_max_y; 259 260 int m_hpixels_per_column; /* number of pixels per video memory address */ 261 262 reconfigure_delegate m_reconfigure_cb; 263 264 /* if specified, this gets called before any pixel update, 265 optionally return a pointer that will be passed to the 266 update and tear down callbacks */ 267 begin_update_delegate m_begin_update_cb; 268 269 /* this gets called for every row, the driver must output 270 x_count * hpixels_per_column pixels. 271 cursor_x indicates the character position where the cursor is, or -1 272 if there is no cursor on this row */ 273 update_row_delegate m_update_row_cb; 274 275 /* if specified, this gets called after all row updating is complete */ 276 end_update_delegate m_end_update_cb; 277 278 /* Called whenever the update address changes 279 * For vblank/hblank timing strobe indicates the physical update. 280 * vblank/hblank timing not supported yet! */ 281 on_update_addr_changed_delegate m_on_update_addr_changed_cb; 282 283 /* if specified, this gets called for every change of the display enable pin (pin 18) */ 284 devcb_write_line m_out_de_cb; 285 286 /* if specified, this gets called for every change of the cursor pin (pin 19) */ 287 devcb_write_line m_out_cur_cb; 288 289 /* if specified, this gets called for every change of the HSYNC pin (pin 39) */ 290 devcb_write_line m_out_hsync_cb; 291 292 /* if specified, this gets called for every change of the VSYNC pin (pin 40) */ 293 devcb_write_line m_out_vsync_cb; 294 }; 295 296 297 class mc6845_1_device : public mc6845_device 298 { 299 public: 300 mc6845_1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); 301 302 protected: 303 virtual void device_start() override; 304 virtual void device_reset() override; 305 }; 306 307 class r6545_1_device : public mc6845_device 308 { 309 public: 310 r6545_1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); 311 312 protected: 313 virtual void device_start() override; 314 virtual void device_reset() override; 315 }; 316 317 class c6545_1_device : public mc6845_device 318 { 319 public: 320 c6545_1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); 321 322 protected: 323 virtual void device_start() override; 324 virtual void device_reset() override; 325 }; 326 327 class hd6845s_device : public mc6845_device 328 { 329 public: 330 hd6845s_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); 331 332 protected: 333 hd6845s_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); 334 335 virtual void device_start() override; 336 virtual void device_reset() override; 337 virtual bool check_cursor_visible(uint16_t ra, uint16_t line_addr) override; 338 }; 339 340 class sy6545_1_device : public mc6845_device 341 { 342 public: 343 sy6545_1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); 344 345 protected: 346 virtual void device_start() override; 347 virtual void device_reset() override; 348 }; 349 350 class sy6845e_device : public mc6845_device 351 { 352 public: 353 sy6845e_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); 354 355 protected: 356 virtual void device_start() override; 357 virtual void device_reset() override; 358 }; 359 360 class hd6345_device : public hd6845s_device 361 { 362 public: 363 hd6345_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); 364 365 void address_w(uint8_t data); 366 uint8_t register_r(); 367 void register_w(uint8_t data); 368 369 protected: 370 virtual void device_start() override; 371 virtual void device_reset() override; 372 373 /* register file */ 374 uint8_t m_disp2_pos; /* 0x12 */ 375 uint16_t m_disp2_start_addr; /* 0x13/0x14 */ 376 uint8_t m_disp3_pos; /* 0x15 */ 377 uint16_t m_disp3_start_addr; /* 0x16/0x17 */ 378 uint8_t m_disp4_pos; /* 0x18 */ 379 uint16_t m_disp4_start_addr; /* 0x19/0x1a */ 380 uint8_t m_vert_sync_pos_adj; /* 0x1b */ 381 uint8_t m_smooth_scroll_ras; /* 0x1d */ 382 uint8_t m_control1; /* 0x1e */ 383 uint8_t m_control2; /* 0x1f */ 384 uint8_t m_control3; /* 0x20 */ 385 uint8_t m_mem_width_offs; /* 0x21 */ 386 uint8_t m_cursor2_start_ras; /* 0x22 */ 387 uint8_t m_cursor2_end_ras; /* 0x23 */ 388 uint16_t m_cursor2_addr; /* 0x24/0x25 */ 389 uint8_t m_cursor_width; /* 0x26 */ 390 uint8_t m_cursor2_width; /* 0x27 */ 391 392 virtual uint8_t draw_scanline(int y, bitmap_rgb32 &bitmap, const rectangle &cliprect) override; 393 }; 394 395 class ams40489_device : public mc6845_device 396 { 397 public: 398 ams40489_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); 399 400 protected: 401 virtual void device_start() override; 402 virtual void device_reset() override; 403 }; 404 405 class mos8563_device : public mc6845_device, 406 public device_memory_interface, 407 public device_palette_interface 408 { 409 public: 410 mos8563_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); 411 412 void address_w(uint8_t data); 413 uint8_t status_r(); 414 uint8_t register_r(); 415 void register_w(uint8_t data); 416 417 inline uint8_t read_videoram(offs_t offset); 418 inline void write_videoram(offs_t offset, uint8_t data); 419 420 MC6845_UPDATE_ROW( vdc_update_row ); 421 422 protected: 423 mos8563_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); 424 425 // device-level overrides 426 virtual void device_start() override; 427 virtual void device_reset() override; 428 virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; 429 430 // device_memory_interface overrides 431 virtual space_config_vector memory_space_config() const override; 432 433 // device_palette_interface overrides palette_entries()434 virtual uint32_t palette_entries() const override { return 16; } 435 436 const address_space_config m_videoram_space_config; 437 438 uint8_t m_char_buffer[80]; 439 uint8_t m_attr_buffer[80]; 440 441 bool m_char_blink_state; 442 uint8_t m_char_blink_count; 443 444 /* register file */ 445 uint16_t m_attribute_addr; /* 0x14/0x15 */ 446 uint8_t m_horiz_char; /* 0x16 */ 447 uint8_t m_vert_char_disp; /* 0x17 */ 448 uint8_t m_vert_scroll; /* 0x18 */ 449 uint8_t m_horiz_scroll; /* 0x19 */ 450 uint8_t m_color; /* 0x1a */ 451 uint8_t m_row_addr_incr; /* 0x1b */ 452 uint8_t m_char_base_addr; /* 0x1c */ 453 uint8_t m_underline_ras; /* 0x1d */ 454 uint8_t m_word_count; /* 0x1e */ 455 uint8_t m_data; /* 0x1f */ 456 uint16_t m_block_addr; /* 0x20/0x21 */ 457 uint16_t m_de_begin; /* 0x22/0x23 */ 458 uint8_t m_dram_refresh; /* 0x24 */ 459 uint8_t m_sync_polarity; /* 0x25 */ 460 461 int m_revision; 462 463 virtual void update_cursor_state() override; 464 virtual uint8_t draw_scanline(int y, bitmap_rgb32 &bitmap, const rectangle &cliprect) override; 465 466 static const device_timer_id TIMER_BLOCK_COPY = 9; 467 468 emu_timer *m_block_copy_timer; 469 470 void mos8563_videoram_map(address_map &map); 471 }; 472 473 class mos8568_device : public mos8563_device 474 { 475 public: 476 mos8568_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); 477 478 protected: 479 // device-level overrides 480 virtual void device_start() override; 481 virtual void device_reset() override; 482 }; 483 484 485 DECLARE_DEVICE_TYPE(MC6845, mc6845_device) 486 DECLARE_DEVICE_TYPE(MC6845_1, mc6845_1_device) 487 DECLARE_DEVICE_TYPE(R6545_1, r6545_1_device) 488 DECLARE_DEVICE_TYPE(C6545_1, c6545_1_device) 489 DECLARE_DEVICE_TYPE(HD6845S, hd6845s_device) 490 DECLARE_DEVICE_TYPE(SY6545_1, sy6545_1_device) 491 DECLARE_DEVICE_TYPE(SY6845E, sy6845e_device) 492 DECLARE_DEVICE_TYPE(HD6345, hd6345_device) 493 DECLARE_DEVICE_TYPE(AMS40489, ams40489_device) 494 DECLARE_DEVICE_TYPE(MOS8563, mos8563_device) 495 DECLARE_DEVICE_TYPE(MOS8568, mos8568_device) 496 497 #endif // MAME_VIDEO_MC6845_H 498