From d5e4b7bd63910148aaca7a0c43f9238786b94ea3 Mon Sep 17 00:00:00 2001 From: Fabio Priuli Date: Mon, 3 Jun 2013 19:17:28 +0000 Subject: [PATCH] (MESS) modernized VT100/Rainbow video device. [Fabio Priuli] --- src/mess/drivers/rainbow.c | 15 +- src/mess/drivers/vt100.c | 11 +- src/mess/video/vtvideo.c | 855 ++++++++++++++++++------------------- src/mess/video/vtvideo.h | 97 +++-- 4 files changed, 500 insertions(+), 478 deletions(-) diff --git a/src/mess/drivers/rainbow.c b/src/mess/drivers/rainbow.c index 8748f18ef65..6bfefdde8e7 100644 --- a/src/mess/drivers/rainbow.c +++ b/src/mess/drivers/rainbow.c @@ -80,12 +80,11 @@ public: m_kbd8251(*this, "kbdser"), m_lk201(*this, LK201_TAG), m_p_ram(*this, "p_ram"), - m_shared(*this, "sh_ram") - , + m_shared(*this, "sh_ram"), m_maincpu(*this, "maincpu") { } - required_device m_crtc; + required_device m_crtc; required_device m_i8088; required_device m_z80; required_device m_fdc; @@ -164,11 +163,11 @@ static ADDRESS_MAP_START( rainbow8088_io , AS_IO, 8, rainbow_state) ADDRESS_MAP_GLOBAL_MASK(0xff) AM_RANGE (0x00, 0x00) AM_READWRITE(i8088_latch_r, i8088_latch_w) // 0x04 Video processor DC011 - AM_RANGE (0x04, 0x04) AM_DEVWRITE_LEGACY("vt100_video", vt_video_dc011_w) + AM_RANGE (0x04, 0x04) AM_DEVWRITE("vt100_video", rainbow_video_device, dc011_w) AM_RANGE (0x0a, 0x0a) AM_READWRITE(diagnostic_r, diagnostic_w) // 0x0C Video processor DC012 - AM_RANGE (0x0c, 0x0c) AM_DEVWRITE_LEGACY("vt100_video", vt_video_dc012_w) + AM_RANGE (0x0c, 0x0c) AM_DEVWRITE("vt100_video", rainbow_video_device, dc012_w) AM_RANGE(0x10, 0x10) AM_DEVREADWRITE("kbdser", i8251_device, data_r, data_w) AM_RANGE(0x11, 0x11) AM_DEVREADWRITE("kbdser", i8251_device, status_r, control_w) @@ -210,8 +209,7 @@ void rainbow_state::machine_reset() UINT32 rainbow_state::screen_update_rainbow(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) { - device_t *devconf = machine().device("vt100_video"); - rainbow_video_update( devconf, bitmap, cliprect); + m_crtc->video_update(bitmap, cliprect); return 0; } @@ -470,7 +468,6 @@ static MACHINE_CONFIG_START( rainbow, rainbow_state ) MCFG_CPU_PROGRAM_MAP(rainbowz80_mem) MCFG_CPU_IO_MAP(rainbowz80_io) - /* video hardware */ MCFG_SCREEN_ADD("screen", RASTER) MCFG_SCREEN_REFRESH_RATE(60) @@ -481,7 +478,7 @@ static MACHINE_CONFIG_START( rainbow, rainbow_state ) MCFG_GFXDECODE(rainbow) MCFG_PALETTE_LENGTH(2) MCFG_PALETTE_INIT(monochrome_green) - MCFG_VT100_VIDEO_ADD("vt100_video", video_interface) + MCFG_RAINBOW_VIDEO_ADD("vt100_video", video_interface) MCFG_FD1793_ADD("wd1793", rainbow_wd17xx_interface ) MCFG_LEGACY_FLOPPY_2_DRIVES_ADD(floppy_intf) diff --git a/src/mess/drivers/vt100.c b/src/mess/drivers/vt100.c index ed03a3808ba..31d2c6a68cf 100644 --- a/src/mess/drivers/vt100.c +++ b/src/mess/drivers/vt100.c @@ -107,7 +107,7 @@ ADDRESS_MAP_END READ8_MEMBER( vt100_state::vt100_flags_r ) { UINT8 ret = 0; - ret |= vt_video_lba7_r(m_crtc, space, 0) << 6; + ret |= m_crtc->lba7_r(space, 0) << 6; ret |= m_keyboard_int << 7; return ret; } @@ -189,7 +189,7 @@ static ADDRESS_MAP_START(vt100_io, AS_IO, 8, vt100_state) // 0x42 Flags buffer AM_RANGE (0x42, 0x42) AM_READ(vt100_flags_r) // 0x42 Brightness D/A latch - AM_RANGE (0x42, 0x42) AM_DEVWRITE_LEGACY("vt100_video", vt_video_brightness_w) + AM_RANGE (0x42, 0x42) AM_DEVWRITE("vt100_video", vt100_video_device, brightness_w) // 0x62 NVR latch AM_RANGE (0x62, 0x62) AM_WRITE(vt100_nvr_latch_w) // 0x82 Keyboard UART data output @@ -197,9 +197,9 @@ static ADDRESS_MAP_START(vt100_io, AS_IO, 8, vt100_state) // 0x82 Keyboard UART data input AM_RANGE (0x82, 0x82) AM_WRITE(vt100_keyboard_w) // 0xA2 Video processor DC012 - AM_RANGE (0xa2, 0xa2) AM_DEVWRITE_LEGACY("vt100_video", vt_video_dc012_w) + AM_RANGE (0xa2, 0xa2) AM_DEVWRITE("vt100_video", vt100_video_device, dc012_w) // 0xC2 Video processor DC011 - AM_RANGE (0xc2, 0xc2) AM_DEVWRITE_LEGACY("vt100_video", vt_video_dc011_w) + AM_RANGE (0xc2, 0xc2) AM_DEVWRITE("vt100_video", vt100_video_device, dc011_w) // 0xE2 Graphics port // AM_RANGE (0xe2, 0xe2) ADDRESS_MAP_END @@ -324,8 +324,7 @@ INPUT_PORTS_END UINT32 vt100_state::screen_update_vt100(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) { - device_t *devconf = machine().device("vt100_video"); - vt_video_update( devconf, bitmap, cliprect); + m_crtc->video_update(bitmap, cliprect); return 0; } diff --git a/src/mess/video/vtvideo.c b/src/mess/video/vtvideo.c index a37bbb44b55..7ac79cb0b46 100644 --- a/src/mess/video/vtvideo.c +++ b/src/mess/video/vtvideo.c @@ -11,7 +11,7 @@ **********************************************************************/ #include "emu.h" -#include "vtvideo.h" +#include "video/vtvideo.h" /*************************************************************************** PARAMETERS @@ -21,438 +21,29 @@ #define LOG(x) do { if (VERBOSE) logerror x; } while (0) -/*************************************************************************** - TYPE DEFINITIONS -***************************************************************************/ - -struct vt_video_t -{ - devcb_resolved_read8 in_ram_func; - devcb_resolved_write8 clear_video_interrupt; - - screen_device *screen; /* screen */ - UINT8 *gfx; /* content of char rom */ - - int lba7; - - // dc012 attributes - UINT8 scroll_latch; - UINT8 blink_flip_flop; - UINT8 reverse_field; - UINT8 basic_attribute; - // dc011 attributes - UINT8 columns; - UINT8 height; - UINT8 skip_lines; - UINT8 frequency; - UINT8 interlaced; -}; - -/*************************************************************************** - INLINE FUNCTIONS -***************************************************************************/ - -INLINE vt_video_t *get_safe_token(device_t *device) -{ - assert(device != NULL); - assert(device->type() == VT100_VIDEO); - - return (vt_video_t *)downcast(device)->token(); -} - -INLINE const vt_video_interface *get_interface(device_t *device) -{ - assert(device != NULL); - assert(device->type() == VT100_VIDEO); - - return (const vt_video_interface *) device->static_config(); -} - -/*************************************************************************** - IMPLEMENTATION -***************************************************************************/ - -static void vt_video_recompute_parameters(device_t *device) -{ - vt_video_t *vt = get_safe_token(device); - int horiz_pix_total = 0; - int vert_pix_total = 0; - rectangle visarea; - - horiz_pix_total = vt->columns * 10; - vert_pix_total = 25 * 10; - - visarea.set(0, horiz_pix_total - 1, 0, vert_pix_total - 1); - - vt->screen->configure(horiz_pix_total, vert_pix_total, visarea, - vt->screen->frame_period().attoseconds); -} -READ8_DEVICE_HANDLER( vt_video_lba7_r ) -{ - vt_video_t *vt = get_safe_token(device); - return vt->lba7; -} - - -WRITE8_DEVICE_HANDLER( vt_video_dc012_w ) -{ - vt_video_t *vt = get_safe_token(device); - - if ((data & 0x08)==0) { - if ((data & 0x04)==0) { - // set lower part scroll - vt->scroll_latch = (vt->scroll_latch & 0x0c) | (data & 0x03); - } else { - // set higher part scroll - vt->scroll_latch = (vt->scroll_latch & 0x03) | ((data & 0x03) << 2); - } - } else { - switch( data & 0x0f) { - case 0x08: - // toggle blink flip flop - vt->blink_flip_flop = (vt->blink_flip_flop==0) ? 1 : 0; - break; - case 0x09: - // clear vertical frequency interrupt; - vt->clear_video_interrupt(0, 0); - break; - case 0x0A: - // set reverse field on - vt->reverse_field = 1; - break; - case 0x0B: - // set reverse field off - vt->reverse_field = 0; - break; - case 0x0C: - // set basic attribute to underline - vt->basic_attribute = 0; - vt->blink_flip_flop = 0; - break; - case 0x0D: - // set basic attribute to reverse video - vt->basic_attribute = 1; - vt->blink_flip_flop = 0; - break; - case 0x0E: - case 0x0F: - // reserved for future specification - vt->blink_flip_flop = 0; - break; - } - } -} - - -WRITE8_DEVICE_HANDLER( vt_video_dc011_w ) -{ - vt_video_t *vt = get_safe_token(device); - if (BIT(data,5)==0) { - UINT8 col = vt->columns; - if (BIT(data,4)==0) { - vt->columns = 80; - } else { - vt->columns = 132; - } - if (col!=vt->columns) { - vt_video_recompute_parameters(device); - } - vt->interlaced = 1; - } else { - if (BIT(data,4)==0) { - vt->frequency = 60; - vt->skip_lines = 2; - } else { - vt->frequency = 50; - vt->skip_lines = 5; - } - vt->interlaced = 0; - } -} - -WRITE8_DEVICE_HANDLER( vt_video_brightness_w ) -{ - //palette_set_color_rgb(space.machine(), 1, data, data, data); -} - -static void vt_video_display_char(device_t *device,bitmap_ind16 &bitmap, UINT8 code, - int x, int y,UINT8 scroll_region,UINT8 display_type) -{ - UINT8 line=0; - int i,b,bit=0,prevbit,invert=0,j; - int double_width = (display_type==2) ? 1 : 0; - vt_video_t *vt = get_safe_token(device); - - for (i = 0; i < 10; i++) - { - switch(display_type) { - case 0 : // bottom half, double height - j = (i >> 1)+5; break; - case 1 : // top half, double height - j = (i >> 1); break; - case 2 : // double width - case 3 : // normal - j = i; break; - default : j = 0; break; - } - // modify line since that is how it is stored in rom - if (j==0) j=15; else j=j-1; - - line = vt->gfx[(code & 0x7f)*16 + j]; - if (vt->basic_attribute==1) { - if ((code & 0x80)==0x80) - invert = 1; - else - invert = 0; - } - - for (b = 0; b < 8; b++) - { - prevbit = bit; - bit = (((line << b) & 0x80) ? 1 : 0); - if (double_width) { - bitmap.pix16(y*10+i, x*20+b*2) = (bit|prevbit)^invert; - bitmap.pix16(y*10+i, x*20+b*2+1) = bit^invert; - } else { - bitmap.pix16(y*10+i, x*10+b) = (bit|prevbit)^invert; - } - } - prevbit = bit; - // char interleave is filled with last bit - if (double_width) { - bitmap.pix16(y*10+i, x*20+16) = (bit|prevbit)^invert; - bitmap.pix16(y*10+i, x*20+17) = bit^invert; - bitmap.pix16(y*10+i, x*20+18) = bit^invert; - bitmap.pix16(y*10+i, x*20+19) = bit^invert; - } else { - bitmap.pix16(y*10+i, x*10+8) = (bit|prevbit)^invert; - bitmap.pix16(y*10+i, x*10+9) = bit^invert; - } - } -} - -void vt_video_update(device_t *device, bitmap_ind16 &bitmap, const rectangle &cliprect) -{ - vt_video_t *vt = get_safe_token(device); - - UINT16 addr = 0; - int line = 0; - int xpos = 0; - int ypos = 0; - UINT8 code; - int x = 0; - UINT8 scroll_region = 1; // binary 1 - UINT8 display_type = 3; // binary 11 - UINT16 temp =0; - - if (vt->in_ram_func(0) !=0x7f) return; - - while(line < (vt->height + vt->skip_lines)) { - code = vt->in_ram_func(addr + xpos); - if (code == 0x7f) { - // end of line, fill empty till end of line - if (line >= vt->skip_lines) { - for(x = xpos; x < ((display_type==2) ? (vt->columns / 2) : vt->columns); x++ ) - { - vt_video_display_char(device,bitmap,code,x,ypos,scroll_region,display_type); - } - } - // move to new data - temp = vt->in_ram_func(addr+xpos+1)*256 + vt->in_ram_func(addr+xpos+2); - addr = (temp) & 0x1fff; - // if A12 is 1 then it is 0x2000 block, if 0 then 0x4000 (AVO) - if (addr & 0x1000) addr &= 0xfff; else addr |= 0x2000; - scroll_region = (temp >> 15) & 1; - display_type = (temp >> 13) & 3; - if (line >= vt->skip_lines) { - ypos++; - } - xpos=0; - line++; - } else { - // display regular char - if (line >= vt->skip_lines) { - vt_video_display_char(device,bitmap,code,xpos,ypos,scroll_region,display_type); - } - xpos++; - if (xpos > vt->columns) { - line++; - xpos=0; - } - } - } - -} - -static void rainbow_video_display_char(device_t *device,bitmap_ind16 &bitmap, UINT8 code, - int x, int y,UINT8 scroll_region,UINT8 display_type) -{ - UINT8 line=0; - int i,b,bit=0,j; - int double_width = (display_type==2) ? 1 : 0; - vt_video_t *vt = get_safe_token(device); - - for (i = 0; i < 10; i++) - { - switch(display_type) { - case 0 : // bottom half, double height - j = (i >> 1)+5; break; - case 1 : // top half, double height - j = (i >> 1); break; - case 2 : // double width - case 3 : // normal - j = i; break; - default : j = 0; break; - } - // modify line since that is how it is stored in rom - if (j==0) j=15; else j=j-1; - - line = vt->gfx[code*16 + j]; - if (vt->basic_attribute==1) { - if ((code & 0x80)==0x80) { - line = line ^ 0xff; - } - } - - for (b = 0; b < 8; b++) - { - bit = ((line << b) & 0x80) ? 1 : 0; - if (double_width) { - bitmap.pix16(y*10+i, x*20+b*2) = bit; - bitmap.pix16(y*10+i, x*20+b*2+1) = bit; - } else { - bitmap.pix16(y*10+i, x*10+b) = bit; - } - } - // char interleave is filled with last bit - if (double_width) { - bitmap.pix16(y*10+i, x*20+16) = bit; - bitmap.pix16(y*10+i, x*20+17) = bit; - bitmap.pix16(y*10+i, x*20+18) = bit; - bitmap.pix16(y*10+i, x*20+19) = bit; - } else { - bitmap.pix16(y*10+i, x*10+8) = bit; - bitmap.pix16(y*10+i, x*10+9) = bit; - } - } -} -void rainbow_video_update(device_t *device, bitmap_ind16 &bitmap, const rectangle &cliprect) -{ - vt_video_t *vt = get_safe_token(device); - - UINT16 addr = 0; - UINT16 attr_addr = 0; - int line = 0; - int xpos = 0; - int ypos = 0; - UINT8 code; - int x = 0; - UINT8 scroll_region = 1; // binary 1 - UINT8 display_type = 3; // binary 11 - UINT16 temp =0; - - while(line < (vt->height + vt->skip_lines)) { - code = vt->in_ram_func(addr + xpos); - if (code == 0xff) { - // end of line, fill empty till end of line - if (line >= vt->skip_lines) { - for(x = xpos; x < ((display_type==2) ? (vt->columns / 2) : vt->columns); x++ ) - { - rainbow_video_display_char(device,bitmap,code,x,ypos,scroll_region,display_type); - } - } - // move to new data - temp = vt->in_ram_func(addr+xpos+2)*256 + vt->in_ram_func(addr+xpos+1); - addr = (temp) & 0x0fff; - attr_addr = ((temp) & 0x1fff) - 2; - // if A12 is 1 then it is 0x2000 block, if 0 then 0x4000 (AVO) - if (temp & 0x1000) attr_addr &= 0xfff; else attr_addr |= 0x1000; - temp = vt->in_ram_func(attr_addr); - scroll_region = (temp) & 1; - display_type = (temp>> 1) & 3; - if (line >= vt->skip_lines) { - ypos++; - } - xpos=0; - line++; - } else { - // display regular char - if (line >= vt->skip_lines) { - rainbow_video_display_char(device,bitmap,code,xpos,ypos,scroll_region,display_type); - } - xpos++; - if (xpos > vt->columns) { - line++; - xpos=0; - } - } - } - -} -/*------------------------------------------------- - DEVICE_START( vt_video ) --------------------------------------------------*/ -static TIMER_CALLBACK(lba7_change) -{ - device_t *device = (device_t *)ptr; - vt_video_t *vt = get_safe_token(device); - - vt->lba7 = (vt->lba7) ? 0 : 1; -} - -static DEVICE_START( vt_video ) -{ - vt_video_t *vt = get_safe_token(device); - const vt_video_interface *intf = get_interface(device); - - /* resolve callbacks */ - vt->in_ram_func.resolve(intf->in_ram_func, *device); - vt->clear_video_interrupt.resolve(intf->clear_video_interrupt, *device); - - /* get the screen device */ - vt->screen = device->machine().device(intf->screen_tag); - assert(vt->screen != NULL); - - vt->gfx = device->machine().root_device().memregion(intf->char_rom_region_tag)->base(); - assert(vt->gfx != NULL); - - // LBA7 is scan line frequency update - device->machine().scheduler().timer_pulse(attotime::from_nsec(31778), FUNC(lba7_change), 0, (void *) device); -} - - -/*------------------------------------------------- - DEVICE_RESET( vt_video ) --------------------------------------------------*/ - -static DEVICE_RESET( vt_video ) -{ - vt_video_t *vt = get_safe_token(device); - palette_set_color_rgb(device->machine(), 0, 0x00, 0x00, 0x00); // black - palette_set_color_rgb(device->machine(), 1, 0xff, 0xff, 0xff); // white - - vt->height = 25; - vt->lba7 = 0; - - vt->scroll_latch = 0; - vt->blink_flip_flop = 0; - vt->reverse_field = 0; - vt->basic_attribute = 0; - - vt->columns = 80; - vt->frequency = 60; - vt->interlaced = 1; - vt->skip_lines = 2; // for 60Hz -} const device_type VT100_VIDEO = &device_creator; +const device_type RAINBOW_VIDEO = &device_creator; + + +vt100_video_device::vt100_video_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, type, name, tag, owner, clock) +{ +} + vt100_video_device::vt100_video_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : device_t(mconfig, VT100_VIDEO, "VT100 Video", tag, owner, clock) + : device_t(mconfig, VT100_VIDEO, "VT100 Video", tag, owner, clock) { - m_token = global_alloc_clear(vt_video_t); } + +rainbow_video_device::rainbow_video_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : vt100_video_device(mconfig, RAINBOW_VIDEO, "Rainbow Video", tag, owner, clock) +{ +} + + //------------------------------------------------- // device_config_complete - perform any // operations now that the configuration is @@ -461,6 +52,19 @@ vt100_video_device::vt100_video_device(const machine_config &mconfig, const char void vt100_video_device::device_config_complete() { + // inherit a copy of the static data + const vt_video_interface *intf = reinterpret_cast(static_config()); + if (intf != NULL) + *static_cast(this) = *intf; + + // or initialize to defaults if none provided + else + { + memset(&m_in_ram_cb, 0, sizeof(m_in_ram_cb)); + memset(&m_clear_video_cb, 0, sizeof(m_clear_video_cb)); + m_screen_tag = ""; + m_char_rom_tag = ""; + } } //------------------------------------------------- @@ -469,7 +73,19 @@ void vt100_video_device::device_config_complete() void vt100_video_device::device_start() { - DEVICE_START_NAME( vt_video )(this); + /* resolve callbacks */ + m_in_ram_func.resolve(m_in_ram_cb, *this); + m_clear_video_interrupt.resolve(m_clear_video_cb, *this); + + /* get the screen device */ + m_screen = machine().device(m_screen_tag); + assert(m_screen != NULL); + + m_gfx = machine().root_device().memregion(m_char_rom_tag)->base(); + assert(m_gfx != NULL); + + // LBA7 is scan line frequency update + machine().scheduler().timer_pulse(attotime::from_nsec(31778), timer_expired_delegate(FUNC(vt100_video_device::lba7_change),this)); } //------------------------------------------------- @@ -478,5 +94,388 @@ void vt100_video_device::device_start() void vt100_video_device::device_reset() { - DEVICE_RESET_NAME( vt_video )(this); + palette_set_color_rgb(machine(), 0, 0x00, 0x00, 0x00); // black + palette_set_color_rgb(machine(), 1, 0xff, 0xff, 0xff); // white + + m_height = 25; + m_lba7 = 0; + + m_scroll_latch = 0; + m_blink_flip_flop = 0; + m_reverse_field = 0; + m_basic_attribute = 0; + + m_columns = 80; + m_frequency = 60; + m_interlaced = 1; + m_skip_lines = 2; // for 60Hz +} + + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +void vt100_video_device::recompute_parameters() +{ + int horiz_pix_total = 0; + int vert_pix_total = 0; + rectangle visarea; + + horiz_pix_total = m_columns * 10; + vert_pix_total = 25 * 10; + + visarea.set(0, horiz_pix_total - 1, 0, vert_pix_total - 1); + + m_screen->configure(horiz_pix_total, vert_pix_total, visarea, m_screen->frame_period().attoseconds); +} + + +READ8_MEMBER( vt100_video_device::lba7_r ) +{ + return m_lba7; +} + + +WRITE8_MEMBER( vt100_video_device::dc012_w ) +{ + if (!(data & 0x08)) + { + if (!(data & 0x04)) + { + // set lower part scroll + m_scroll_latch = (m_scroll_latch & 0x0c) | (data & 0x03); + } + else + { + // set higher part scroll + m_scroll_latch = (m_scroll_latch & 0x03) | ((data & 0x03) << 2); + } + } + else + { + switch (data & 0x0f) + { + case 0x08: + // toggle blink flip flop + m_blink_flip_flop = !(m_blink_flip_flop) ? 1 : 0; + break; + case 0x09: + // clear vertical frequency interrupt; + m_clear_video_interrupt(0, 0); + break; + case 0x0a: + // set reverse field on + m_reverse_field = 1; + break; + case 0x0b: + // set reverse field off + m_reverse_field = 0; + break; + case 0x0c: + // set basic attribute to underline + m_basic_attribute = 0; + m_blink_flip_flop = 0; + break; + case 0x0d: + // set basic attribute to reverse video + m_basic_attribute = 1; + m_blink_flip_flop = 0; + break; + case 0x0e: + case 0x0f: + // reserved for future specification + m_blink_flip_flop = 0; + break; + } + } +} + + +WRITE8_MEMBER( vt100_video_device::dc011_w ) +{ + if (!BIT(data, 5)) + { + UINT8 col = m_columns; + if (!BIT(data, 4)) + { + m_columns = 80; + } + else + { + m_columns = 132; + } + if (col != m_columns) + { + recompute_parameters(); + } + m_interlaced = 1; + } + else + { + if (!BIT(data, 4)) + { + m_frequency = 60; + m_skip_lines = 2; + } + else + { + m_frequency = 50; + m_skip_lines = 5; + } + m_interlaced = 0; + } +} + +WRITE8_MEMBER( vt100_video_device::brightness_w ) +{ + //palette_set_color_rgb(machine(), 1, data, data, data); +} + +void vt100_video_device::display_char(bitmap_ind16 &bitmap, UINT8 code, int x, int y, UINT8 scroll_region, UINT8 display_type) +{ + UINT8 line = 0; + int bit = 0, prevbit, invert = 0, j; + int double_width = (display_type == 2) ? 1 : 0; + + for (int i = 0; i < 10; i++) + { + switch (display_type) + { + case 0 : // bottom half, double height + j = (i >> 1) + 5; break; + case 1 : // top half, double height + j = (i >> 1); break; + case 2 : // double width + case 3 : // normal + j = i; break; + default : j = 0; break; + } + // modify line since that is how it is stored in rom + if (j == 0) j = 15; else j = j - 1; + + line = m_gfx[(code & 0x7f) * 16 + j]; + + if (m_basic_attribute == 1) + { + if ((code & 0x80) == 0x80) + invert = 1; + else + invert = 0; + } + + for (int b = 0; b < 8; b++) + { + prevbit = bit; + bit = BIT((line << b), 7); + if (double_width) + { + bitmap.pix16(y * 10 + i, x * 20 + b * 2) = (bit | prevbit) ^ invert; + bitmap.pix16(y * 10 + i, x * 20 + b * 2 + 1) = bit ^ invert; + } + else + { + bitmap.pix16(y * 10 + i, x * 10 + b) = (bit | prevbit) ^ invert; + } + } + prevbit = bit; + // char interleave is filled with last bit + if (double_width) + { + bitmap.pix16(y * 10 + i, x * 20 + 16) = (bit | prevbit) ^ invert; + bitmap.pix16(y * 10 + i, x * 20 + 17) = bit ^ invert; + bitmap.pix16(y * 10 + i, x * 20 + 18) = bit ^ invert; + bitmap.pix16(y * 10 + i, x * 20 + 19) = bit ^ invert; + } + else + { + bitmap.pix16(y * 10 + i, x * 10 + 8) = (bit | prevbit) ^ invert; + bitmap.pix16(y * 10 + i, x * 10 + 9) = bit ^ invert; + } + } +} + +void vt100_video_device::video_update(bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + UINT16 addr = 0; + int line = 0; + int xpos = 0; + int ypos = 0; + UINT8 code; + int x = 0; + UINT8 scroll_region = 1; // binary 1 + UINT8 display_type = 3; // binary 11 + UINT16 temp = 0; + + if (m_in_ram_func(0) != 0x7f) + return; + + while (line < (m_height + m_skip_lines)) + { + code = m_in_ram_func(addr + xpos); + if (code == 0x7f) + { + // end of line, fill empty till end of line + if (line >= m_skip_lines) + { + for (x = xpos; x < ((display_type == 2) ? (m_columns / 2) : m_columns); x++) + { + display_char(bitmap, code, x, ypos, scroll_region, display_type); + } + } + // move to new data + temp = m_in_ram_func(addr + xpos + 1) * 256 + m_in_ram_func(addr + xpos + 2); + addr = (temp) & 0x1fff; + // if A12 is 1 then it is 0x2000 block, if 0 then 0x4000 (AVO) + if (addr & 0x1000) addr &= 0xfff; else addr |= 0x2000; + scroll_region = (temp >> 15) & 1; + display_type = (temp >> 13) & 3; + if (line >= m_skip_lines) + { + ypos++; + } + xpos = 0; + line++; + } + else + { + // display regular char + if (line >= m_skip_lines) + { + display_char(bitmap, code, xpos, ypos, scroll_region, display_type); + } + xpos++; + if (xpos > m_columns) + { + line++; + xpos = 0; + } + } + } + +} + +void rainbow_video_device::display_char(bitmap_ind16 &bitmap, UINT8 code, int x, int y, UINT8 scroll_region, UINT8 display_type) +{ + UINT8 line = 0; + int bit = 0, j; + int double_width = (display_type == 2) ? 1 : 0; + + for (int i = 0; i < 10; i++) + { + switch (display_type) + { + case 0 : // bottom half, double height + j = (i >> 1) + 5; break; + case 1 : // top half, double height + j = (i >> 1); break; + case 2 : // double width + case 3 : // normal + j = i; break; + default : j = 0; break; + } + // modify line since that is how it is stored in rom + if (j == 0) j = 15; else j = j - 1; + + line = m_gfx[code * 16 + j]; + if (m_basic_attribute == 1) + { + if ((code & 0x80) == 0x80) + { + line = line ^ 0xff; + } + } + + for (int b = 0; b < 8; b++) + { + bit = BIT((line << b), 7); + if (double_width) + { + bitmap.pix16(y * 10 + i, x * 20 + b * 2) = bit; + bitmap.pix16(y * 10 + i, x * 20 + b * 2 + 1) = bit; + } + else + { + bitmap.pix16(y * 10 + i, x * 10 + b) = bit; + } + } + // char interleave is filled with last bit + if (double_width) + { + bitmap.pix16(y * 10 + i, x * 20 + 16) = bit; + bitmap.pix16(y * 10 + i, x * 20 + 17) = bit; + bitmap.pix16(y * 10 + i, x * 20 + 18) = bit; + bitmap.pix16(y * 10 + i, x * 20 + 19) = bit; + } + else + { + bitmap.pix16(y * 10 + i, x * 10 + 8) = bit; + bitmap.pix16(y * 10 + i, x * 10 + 9) = bit; + } + } +} + +void rainbow_video_device::video_update(bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + UINT16 addr = 0; + UINT16 attr_addr = 0; + int line = 0; + int xpos = 0; + int ypos = 0; + UINT8 code; + int x = 0; + UINT8 scroll_region = 1; // binary 1 + UINT8 display_type = 3; // binary 11 + UINT16 temp = 0; + + while (line < (m_height + m_skip_lines)) + { + code = m_in_ram_func(addr + xpos); + if (code == 0xff) + { + // end of line, fill empty till end of line + if (line >= m_skip_lines) + { + for (x = xpos; x < ((display_type == 2) ? (m_columns / 2) : m_columns); x++) + { + display_char(bitmap, code, x, ypos, scroll_region, display_type); + } + } + // move to new data + temp = m_in_ram_func(addr + xpos + 2) * 256 + m_in_ram_func(addr + xpos + 1); + addr = (temp) & 0x0fff; + attr_addr = ((temp) & 0x1fff) - 2; + // if A12 is 1 then it is 0x2000 block, if 0 then 0x4000 (AVO) + if (temp & 0x1000) attr_addr &= 0xfff; else attr_addr |= 0x1000; + temp = m_in_ram_func(attr_addr); + scroll_region = (temp) & 1; + display_type = (temp>> 1) & 3; + if (line >= m_skip_lines) + { + ypos++; + } + xpos = 0; + line++; + } + else + { + // display regular char + if (line >= m_skip_lines) + { + display_char(bitmap, code, xpos, ypos, scroll_region, display_type); + } + xpos++; + if (xpos > m_columns) + { + line++; + xpos = 0; + } + } + } + +} + +TIMER_CALLBACK_MEMBER( vt100_video_device::lba7_change ) +{ + m_lba7 = (m_lba7) ? 0 : 1; } diff --git a/src/mess/video/vtvideo.h b/src/mess/video/vtvideo.h index 1d59ddc7ff0..8c7b1323058 100644 --- a/src/mess/video/vtvideo.h +++ b/src/mess/video/vtvideo.h @@ -14,62 +14,89 @@ #define __VT_VIDEO__ #include "emu.h" -#include "devcb.h" -/*************************************************************************** - MACROS / CONSTANTS -***************************************************************************/ +struct vt_video_interface +{ + const char *m_screen_tag; /* screen we are acting on */ + const char *m_char_rom_tag; /* character rom region */ + + /* this gets called for every memory read */ + devcb_read8 m_in_ram_cb; + devcb_write8 m_clear_video_cb; +}; -class vt100_video_device : public device_t + +class vt100_video_device : public device_t, + public vt_video_interface { public: + vt100_video_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock); vt100_video_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); - ~vt100_video_device() { global_free(m_token); } + ~vt100_video_device() {} + + DECLARE_READ8_MEMBER(lba7_r); + DECLARE_WRITE8_MEMBER(dc012_w); + DECLARE_WRITE8_MEMBER(dc011_w); + DECLARE_WRITE8_MEMBER(brightness_w); + + virtual void video_update(bitmap_ind16 &bitmap, const rectangle &cliprect); - // access to legacy token - void *token() const { assert(m_token != NULL); return m_token; } protected: // device-level overrides virtual void device_config_complete(); virtual void device_start(); virtual void device_reset(); -private: + // internal state - void *m_token; + void recompute_parameters(); + virtual void display_char(bitmap_ind16 &bitmap, UINT8 code, int x, int y, UINT8 scroll_region, UINT8 display_type); + TIMER_CALLBACK_MEMBER(lba7_change); + + devcb_resolved_read8 m_in_ram_func; + devcb_resolved_write8 m_clear_video_interrupt; + + screen_device *m_screen; /* screen */ + UINT8 *m_gfx; /* content of char rom */ + + int m_lba7; + + // dc012 attributes + UINT8 m_scroll_latch; + UINT8 m_blink_flip_flop; + UINT8 m_reverse_field; + UINT8 m_basic_attribute; + // dc011 attributes + UINT8 m_columns; + UINT8 m_height; + UINT8 m_skip_lines; + UINT8 m_frequency; + UINT8 m_interlaced; +}; + + +class rainbow_video_device : public vt100_video_device +{ +public: + rainbow_video_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual void video_update(bitmap_ind16 &bitmap, const rectangle &cliprect); + +protected: + virtual void display_char(bitmap_ind16 &bitmap, UINT8 code, int x, int y, UINT8 scroll_region, UINT8 display_type); + }; extern const device_type VT100_VIDEO; +extern const device_type RAINBOW_VIDEO; #define MCFG_VT100_VIDEO_ADD(_tag, _intrf) \ MCFG_DEVICE_ADD(_tag, VT100_VIDEO, 0) \ MCFG_DEVICE_CONFIG(_intrf) -/*************************************************************************** - TYPE DEFINITIONS -***************************************************************************/ -struct vt_video_interface -{ - const char *screen_tag; /* screen we are acting on */ - const char *char_rom_region_tag; /* character rom region */ +#define MCFG_RAINBOW_VIDEO_ADD(_tag, _intrf) \ + MCFG_DEVICE_ADD(_tag, RAINBOW_VIDEO, 0) \ + MCFG_DEVICE_CONFIG(_intrf) - /* this gets called for every memory read */ - devcb_read8 in_ram_func; - devcb_write8 clear_video_interrupt; -}; - -/*************************************************************************** - PROTOTYPES -***************************************************************************/ -/* register access */ -DECLARE_READ8_DEVICE_HANDLER ( vt_video_lba7_r ); -DECLARE_WRITE8_DEVICE_HANDLER ( vt_video_dc012_w ); -DECLARE_WRITE8_DEVICE_HANDLER ( vt_video_dc011_w ); -DECLARE_WRITE8_DEVICE_HANDLER ( vt_video_brightness_w ); - - -/* screen update */ -void vt_video_update(device_t *device, bitmap_ind16 &bitmap, const rectangle &cliprect); -void rainbow_video_update(device_t *device, bitmap_ind16 &bitmap, const rectangle &cliprect); #endif