(MESS) modernized VT100/Rainbow video device. [Fabio Priuli]

This commit is contained in:
Fabio Priuli 2013-06-03 19:17:28 +00:00
parent e49edb8fb1
commit d5e4b7bd63
4 changed files with 500 additions and 478 deletions

View File

@ -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<vt100_video_device> m_crtc;
required_device<rainbow_video_device> m_crtc;
required_device<cpu_device> m_i8088;
required_device<cpu_device> m_z80;
required_device<fd1793_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)

View File

@ -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;
}

View File

@ -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<vt100_video_device *>(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<screen_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<vt100_video_device>;
const device_type RAINBOW_VIDEO = &device_creator<rainbow_video_device>;
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<const vt_video_interface *>(static_config());
if (intf != NULL)
*static_cast<vt_video_interface *>(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<screen_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;
}

View File

@ -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