diff options
Diffstat (limited to 'src/mame/video/uv201.c')
-rw-r--r-- | src/mame/video/uv201.c | 589 |
1 files changed, 589 insertions, 0 deletions
diff --git a/src/mame/video/uv201.c b/src/mame/video/uv201.c new file mode 100644 index 00000000000..ae18cee5d2d --- /dev/null +++ b/src/mame/video/uv201.c @@ -0,0 +1,589 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + VideoBrain UV201/UV202 video chip emulation + +**********************************************************************/ + +#include "uv201.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 1 + + +// screen parameters +#define SCREEN_WIDTH 232 +#define SCREEN_HEIGHT 262 +#define VISAREA_WIDTH 193 +#define VBLANK_WIDTH 21 +#define HBLANK_WIDTH 39 +#define HSYNC_WIDTH 18 +#define HFP_WIDTH 16 +#define HBP_WIDTH 5 +#define HBLANK_END HSYNC_WIDTH + HFP_WIDTH +#define HBLANK_START HBLANK_END + VISAREA_WIDTH + + +// write-only registers +#define REGISTER_COMMAND 0xf7 +#define REGISTER_BACKGROUND 0xf5 +#define REGISTER_FINAL_MODIFIER 0xf2 +#define REGISTER_Y_INTERRUPT 0xf0 + + +// read-only registers +#define REGISTER_X_FREEZE 0xf8 +#define REGISTER_Y_FREEZE_LOW 0xf9 +#define REGISTER_Y_FREEZE_HIGH 0xfa +#define REGISTER_CURRENT_Y_LOW 0xfb + + +// read/write registers - RAM memory +#define RAM_RP_LO 0x00 // cartridge pointer low order +#define RAM_RP_HI_COLOR 0x10 // cartridge pointer high order and color +#define RAM_DX_INT_XCOPY 0x20 // dX, intensity, X-copy +#define RAM_DY 0x30 // dY +#define RAM_X 0x40 // X value +#define RAM_Y_LO_A 0x50 // Y value low order list A +#define RAM_Y_LO_B 0x60 // Y value low order list B +#define RAM_XY_HI_A 0x70 // Y value high order and X order list A +#define RAM_XY_HI_B 0x80 // Y value high order and X order list B + + +// command register bits +#define COMMAND_YINT_H_O 0x80 +#define COMMAND_A_B 0x40 +#define COMMAND_Y_ZM 0x20 +#define COMMAND_KBD 0x10 +#define COMMAND_INT 0x08 +#define COMMAND_ENB 0x04 +#define COMMAND_FRZ 0x02 +#define COMMAND_X_ZM 0x01 + + +#define IS_CHANGED(_bit) \ + ((m_cmd & _bit) != (data & _bit)) + +#define RAM(_offset) \ + m_ram[_offset + i] + +#define RAM_XORD(_offset) \ + m_ram[_offset + xord] + +#define IS_VISIBLE(_y) \ + ((_y >= cliprect.min_y) && (_y <= cliprect.max_y)) + +#define DRAW_PIXEL(_scanline, _dot) \ + if (IS_VISIBLE(_scanline)) bitmap.pix32((_scanline), HSYNC_WIDTH + HFP_WIDTH + _dot) = m_palette_val[pixel]; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +// device type definition +const device_type UV201 = &device_creator<uv201_device>; + + +//------------------------------------------------- +// uv201_device - constructor +//------------------------------------------------- + +uv201_device::uv201_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, UV201, "UV201", tag, owner, clock, "uv201", __FILE__), + device_video_interface(mconfig, *this), + m_write_ext_int(*this), + m_write_hblank(*this), + m_read_db(*this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void uv201_device::device_start() +{ + // resolve callbacks + m_write_ext_int.resolve_safe(); + m_write_hblank.resolve_safe(); + m_read_db.resolve_safe(0); + + // allocate timers + m_timer_y_odd = timer_alloc(TIMER_Y_ODD); + m_timer_y_even = timer_alloc(TIMER_Y_EVEN); + m_timer_hblank_on = timer_alloc(TIMER_HBLANK_ON); + m_timer_hblank_off = timer_alloc(TIMER_HBLANK_OFF); + + initialize_palette(); + + memset(m_ram, 0x00, sizeof(m_ram)); + m_y_int = 0; + m_fmod = 0; + m_bg = 0; + m_cmd = 0; + m_freeze_x = 0; + m_freeze_y = 0; + m_field = 0; + + // state saving + save_item(NAME(m_ram)); + save_item(NAME(m_y_int)); + save_item(NAME(m_fmod)); + save_item(NAME(m_bg)); + save_item(NAME(m_cmd)); + save_item(NAME(m_freeze_x)); + save_item(NAME(m_freeze_y)); + save_item(NAME(m_field)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void uv201_device::device_reset() +{ + m_write_ext_int(CLEAR_LINE); + + m_write_hblank(1); + m_timer_hblank_off->adjust(attotime::from_ticks( HBLANK_END, m_clock )); +} + + +//------------------------------------------------- +// device_timer - handle timer events +//------------------------------------------------- + +void uv201_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + int scanline = m_screen->vpos(); + + switch (id) + { + case TIMER_Y_ODD: + case TIMER_Y_EVEN: + if ((m_cmd & COMMAND_INT) && !(m_cmd & COMMAND_FRZ)) + { + if (LOG) logerror("Y-Interrupt at scanline %u\n", scanline); + + m_freeze_y = scanline; + + m_write_ext_int(ASSERT_LINE); + m_write_ext_int(CLEAR_LINE); + } + break; + + case TIMER_HBLANK_ON: + m_write_hblank(1); + + m_timer_hblank_off->adjust(attotime::from_ticks( HBLANK_WIDTH, m_clock ) ); + break; + + case TIMER_HBLANK_OFF: + m_write_hblank(0); + + m_timer_hblank_on->adjust(attotime::from_ticks( VISAREA_WIDTH, m_clock ) ); + break; + } +} + + +//------------------------------------------------- +// initialize_palette - +//------------------------------------------------- + +void uv201_device::initialize_palette() +{ + UINT8 offlointensity = 0x00; + UINT8 offhiintensity = 0xc0; + + UINT8 onlointensity = 0xa0; + UINT8 onhiintensity = 0xff; + + for (int i = 0; i < 4; i++) + { + int offset = i * 8; + UINT8 onvalue, offvalue; + + if (offset < 16) + { + offvalue = offlointensity; + onvalue = onlointensity; + } + else + { + offvalue = offhiintensity; + onvalue = onhiintensity; + } + + m_palette_val[offset + 0] = rgb_t(offvalue, offvalue, offvalue); // black + m_palette_val[offset + 1] = rgb_t(onvalue, offvalue, offvalue); // red + m_palette_val[offset + 2] = rgb_t(offvalue, onvalue, offvalue); // green + m_palette_val[offset + 3] = rgb_t(onvalue, onvalue, offvalue); // red-green + m_palette_val[offset + 4] = rgb_t(offvalue, offvalue, onvalue); // blue + m_palette_val[offset + 5] = rgb_t(onvalue, offvalue, onvalue); // red-blue + m_palette_val[offset + 6] = rgb_t(offvalue, onvalue, onvalue); // green-blue + m_palette_val[offset + 7] = rgb_t(onvalue, onvalue, onvalue); // white + } +} + + +//------------------------------------------------- +// get_field_vpos - get scanline within field +//------------------------------------------------- + +int uv201_device::get_field_vpos() +{ + int vpos = m_screen->vpos(); + + if (vpos >= SCREEN_HEIGHT) + { + // even field + vpos -= SCREEN_HEIGHT; + } + + return vpos; +} + + +//------------------------------------------------- +// get_field - get video field +//------------------------------------------------- + +int uv201_device::get_field() +{ + return m_screen->vpos() < SCREEN_HEIGHT; +} + + +//------------------------------------------------- +// set_y_interrupt - set Y interrupt timer +//------------------------------------------------- + +void uv201_device::set_y_interrupt() +{ + int scanline = ((m_cmd & COMMAND_YINT_H_O) << 1) | m_y_int; + + m_timer_y_odd->adjust(m_screen->time_until_pos(scanline), 0, m_screen->frame_period()); + //m_timer_y_even->adjust(m_screen->time_until_pos(scanline + SCREEN_HEIGHT), 0, m_screen->frame_period()); +} + + +//------------------------------------------------- +// do_partial_update - update screen +//------------------------------------------------- + +void uv201_device::do_partial_update() +{ + int vpos = m_screen->vpos(); + + if (LOG) logerror("Partial screen update at scanline %u\n", vpos); + + m_screen->update_partial(vpos); +} + + +//------------------------------------------------- +// read - +//------------------------------------------------- + +READ8_MEMBER( uv201_device::read ) +{ + UINT8 data = 0xff; + + switch (offset) + { + case REGISTER_X_FREEZE: + data = m_freeze_x; + + if (LOG) logerror("X-Freeze %02x\n", data); + break; + + case REGISTER_Y_FREEZE_LOW: + data = m_freeze_y & 0xff; + + if (LOG) logerror("Y-Freeze Low %02x\n", data); + break; + + case REGISTER_Y_FREEZE_HIGH: + /* + + bit signal description + + 0 Y-F8 Y freeze high order (MSB) bit + 1 Y-C8 current Y counter high order (MSB) bit + 2 + 3 + 4 + 5 + 6 + 7 O/_E odd/even field + + */ + + data = (get_field() << 7) | (BIT(get_field_vpos(), 8) << 1) | BIT(m_freeze_y, 8); + + if (LOG) logerror("Y-Freeze High %02x\n", data); + break; + + case REGISTER_CURRENT_Y_LOW: + data = get_field_vpos() & 0xff; + + if (LOG) logerror("Current-Y Low %02x\n", data); + break; + + default: + if (offset < 0x90) + data = m_ram[offset]; + else + if (LOG) logerror("Unknown VLSI read from %02x!\n", offset); + } + + return data; +} + + +//------------------------------------------------- +// write - +//------------------------------------------------- + +WRITE8_MEMBER( uv201_device::write ) +{ + switch (offset) + { + case REGISTER_Y_INTERRUPT: + if (LOG) logerror("Y-Interrupt %02x\n", data); + + if (m_y_int != data) + { + m_y_int = data; + set_y_interrupt(); + } + break; + + case REGISTER_FINAL_MODIFIER: + /* + + bit signal description + + 0 RED red + 1 GREEN green + 2 BLUE blue + 3 INT 0 intensity 0 + 4 INT 1 intensity 1 + 5 not used + 6 not used + 7 not used + + */ + + if (LOG) logerror("Final Modifier %02x\n", data); + + do_partial_update(); + m_fmod = data & 0x1f; + break; + + case REGISTER_BACKGROUND: + /* + + bit signal description + + 0 RED red + 1 GREEN green + 2 BLUE blue + 3 INT 0 intensity 0 + 4 INT 1 intensity 1 + 5 not used + 6 not used + 7 not used + + */ + + if (LOG) logerror("Background %02x\n", data); + + do_partial_update(); + m_bg = data & 0x1f; + break; + + case REGISTER_COMMAND: + /* + + bit signal description + + 0 X-ZM X zoom + 1 FRZ freeze + 2 ENB video enable + 3 INT interrupt enable + 4 KBD general purpose output + 5 Y-ZM Y zoom + 6 A/_B list selection + 7 YINT H.O. Y COMMAND_INT register high order bit + + */ + + if (LOG) logerror("Command %02x\n", data); + + if (IS_CHANGED(COMMAND_YINT_H_O)) + { + set_y_interrupt(); + } + + if (IS_CHANGED(COMMAND_A_B) || IS_CHANGED(COMMAND_Y_ZM) || IS_CHANGED(COMMAND_X_ZM)) + { + do_partial_update(); + } + + m_cmd = data; + break; + + default: + if (offset < 0x90) + m_ram[offset] = data; + else + logerror("Unknown VLSI write %02x to %02x!\n", data, offset); + } +} + + +//------------------------------------------------- +// ext_int_w - external interrupt write +//------------------------------------------------- + +WRITE_LINE_MEMBER( uv201_device::ext_int_w ) +{ + if (!state && (m_cmd & COMMAND_FRZ)) + { + m_freeze_y = get_field_vpos(); + m_freeze_x = m_screen->hpos(); + } +} + + +//------------------------------------------------- +// kbd_r - keyboard select read +//------------------------------------------------- + +READ_LINE_MEMBER( uv201_device::kbd_r ) +{ + return (m_cmd & COMMAND_KBD) ? 1 : 0; +} + + +//------------------------------------------------- +// screen_update - +//------------------------------------------------- + +UINT32 uv201_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + bitmap.fill(rgb_t(0x00,0x00,0x00), cliprect); + + if (!(m_cmd & COMMAND_ENB)) + { + return 0; + } + + for (int y = 0; y < SCREEN_HEIGHT; y++) + { + for (int x = 0; x < VISAREA_WIDTH; x++) + { + int pixel = m_bg; + DRAW_PIXEL(y, x); + } + } + + for (int i = 0; i < 16; i++) + { + UINT8 xy_hi = (m_cmd & COMMAND_A_B) ? RAM(RAM_XY_HI_A) : RAM(RAM_XY_HI_B); + UINT8 y_lo = (m_cmd & COMMAND_A_B) ? RAM(RAM_Y_LO_A) : RAM(RAM_Y_LO_B); + UINT16 y = (BIT(xy_hi, 7) << 8) | y_lo; + int xord = xy_hi & 0x0f; + + UINT8 rp_hi_color = RAM_XORD(RAM_RP_HI_COLOR); + UINT8 rp_lo = RAM_XORD(RAM_RP_LO); + UINT16 rp = ((rp_hi_color << 8) | rp_lo) & 0x1fff; + + if (rp < 0x800) rp |= 0x2000; + + UINT8 dx_int_xcopy = RAM_XORD(RAM_DX_INT_XCOPY); + int color = ((dx_int_xcopy & 0x60) >> 2) | (BIT(rp_hi_color, 5) << 2) | (BIT(rp_hi_color, 6) << 1) | (BIT(rp_hi_color, 7)); + UINT8 dx = dx_int_xcopy & 0x1f; + UINT8 dy = RAM_XORD(RAM_DY); + int xcopy = BIT(dx_int_xcopy, 7); + UINT8 x = RAM_XORD(RAM_X); + + if (LOG) logerror("Object %u xord %u y %u x %u dy %u dx %u xcopy %u color %u rp %04x\n", i, xord, y, x, dy, dx, xcopy, color, rp); + + if (rp == 0) continue; + if (y > SCREEN_HEIGHT) continue; + + for (int sy = 0; sy < dy; sy++) + { + for (int sx = 0; sx < dx; sx++) + { + UINT8 data = m_read_db(rp); + + for (int bit = 0; bit < 8; bit++) + { + int pixel = ((BIT(data, 7) ? color : m_bg) ^ m_fmod) & 0x1f; + + if (m_cmd & COMMAND_Y_ZM) + { + int scanline = y + (sy * 2); + + if (m_cmd & COMMAND_X_ZM) + { + int dot = (x * 2) + (sx * 16) + (bit * 2); + + DRAW_PIXEL(scanline, dot); + DRAW_PIXEL(scanline, dot + 1); + DRAW_PIXEL(scanline + 1, dot); + DRAW_PIXEL(scanline + 1, dot + 1); + } + else + { + int dot = x + (sx * 8) + bit; + + DRAW_PIXEL(scanline, dot); + DRAW_PIXEL(scanline + 1, dot); + } + } + else + { + int scanline = y + sy; + + if (m_cmd & COMMAND_X_ZM) + { + int dot = (x * 2) + (sx * 16) + (bit * 2); + + DRAW_PIXEL(scanline, dot); + DRAW_PIXEL(scanline, dot + 1); + } + else + { + int dot = x + (sx * 8) + bit; + + DRAW_PIXEL(scanline, dot); + } + } + + data <<= 1; + } + + if (!xcopy) rp++; + } + + if (xcopy) rp++; + } + } + + return 0; +} |