mirror of
https://github.com/holub/mame
synced 2025-04-19 23:12:11 +03:00
(MESS) modernized VT100/Rainbow video device. [Fabio Priuli]
This commit is contained in:
parent
e49edb8fb1
commit
d5e4b7bd63
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user