diff options
Diffstat (limited to 'src/mame/video/zx8301.c')
-rw-r--r-- | src/mame/video/zx8301.c | 334 |
1 files changed, 334 insertions, 0 deletions
diff --git a/src/mame/video/zx8301.c b/src/mame/video/zx8301.c new file mode 100644 index 00000000000..a7c115e8237 --- /dev/null +++ b/src/mame/video/zx8301.c @@ -0,0 +1,334 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Sinclair ZX8301 emulation + +**********************************************************************/ + +/* + + TODO: + + - wait state on memory access during video update + - proper video timing + - get rid of flash timer + +*/ + +#include "zx8301.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + + +// low resolution palette +static const int ZX8301_COLOR_MODE4[] = { 0, 2, 4, 7 }; + + +static const rgb_t PALETTE_ZX8301[] = +{ + rgb_t(0x00, 0x00, 0x00), // black + rgb_t(0x00, 0x00, 0xff), // blue + rgb_t(0xff, 0x00, 0x00), // red + rgb_t(0xff, 0x00, 0xff), // magenta + rgb_t(0x00, 0xff, 0x00), // green + rgb_t(0x00, 0xff, 0xff), // cyan + rgb_t(0xff, 0xff, 0x00), // yellow + rgb_t(0xff, 0xff, 0xff) // white +}; + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// devices +const device_type ZX8301 = &device_creator<zx8301_device>; + + +// default address map +static ADDRESS_MAP_START( zx8301, AS_0, 8, zx8301_device ) + AM_RANGE(0x00000, 0x1ffff) AM_RAM +ADDRESS_MAP_END + + +//------------------------------------------------- +// memory_space_config - return a description of +// any address spaces owned by this device +//------------------------------------------------- + +const address_space_config *zx8301_device::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == AS_0) ? &m_space_config : NULL; +} + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// readbyte - read a byte at the given address +//------------------------------------------------- + +inline UINT8 zx8301_device::readbyte(offs_t address) +{ + return space().read_byte(address); +} + + +//------------------------------------------------- +// writebyte - write a byte at the given address +//------------------------------------------------- + +inline void zx8301_device::writebyte(offs_t address, UINT8 data) +{ + space().write_byte(address, data); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// zx8301_device - constructor +//------------------------------------------------- + +zx8301_device::zx8301_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, ZX8301, "Sinclair ZX8301", tag, owner, clock, "zx8301", __FILE__), + device_memory_interface(mconfig, *this), + device_video_interface(mconfig, *this), + m_space_config("videoram", ENDIANNESS_LITTLE, 8, 17, 0, NULL, *ADDRESS_MAP_NAME(zx8301)), + m_cpu(*this), + m_write_vsync(*this), + m_dispoff(1), + m_mode8(0), + m_base(0), + m_flash(1), + m_vsync(1), + m_vda(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void zx8301_device::device_start() +{ + // resolve callbacks + m_write_vsync.resolve_safe(); + + // allocate timers + m_vsync_timer = timer_alloc(TIMER_VSYNC); + m_flash_timer = timer_alloc(TIMER_FLASH); + + // adjust timer periods + m_vsync_timer->adjust(attotime::zero, 0, attotime::from_hz(50)); + m_flash_timer->adjust(attotime::from_hz(2), 0, attotime::from_hz(2)); + + // register for state saving + save_item(NAME(m_dispoff)); + save_item(NAME(m_mode8)); + save_item(NAME(m_base)); + save_item(NAME(m_flash)); + save_item(NAME(m_vsync)); + save_item(NAME(m_vda)); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void zx8301_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TIMER_VSYNC: + //m_vsync = !m_vsync; + m_write_vsync(m_vsync); + break; + + case TIMER_FLASH: + m_flash = !m_flash; + break; + } +} + + +//------------------------------------------------- +// control_w - display control register +//------------------------------------------------- + +WRITE8_MEMBER( zx8301_device::control_w ) +{ + /* + + bit description + + 0 + 1 display off + 2 + 3 graphics mode + 4 + 5 + 6 + 7 display base address + + */ + + if (LOG) logerror("ZX8301 Control: %02x\n", data); + + // display off + m_dispoff = BIT(data, 1); + + // graphics mode + m_mode8 = BIT(data, 3); + + // display base address + m_base = BIT(data, 7); +} + + +//------------------------------------------------- +// data_r - RAM read +//------------------------------------------------- + +READ8_MEMBER( zx8301_device::data_r ) +{ + if (LOG) logerror("ZX8301 RAM Read: %06x\n", offset); + + if (m_vda) + { + m_cpu->spin_until_time(m_screen->time_until_pos(256, 0)); + } + + return readbyte(offset); +} + + +//------------------------------------------------- +// data_w - RAM write +//------------------------------------------------- + +WRITE8_MEMBER( zx8301_device::data_w ) +{ + if (LOG) logerror("ZX8301 RAM Write: %06x = %02x\n", offset, data); + + if (m_vda) + { + m_cpu->spin_until_time(m_screen->time_until_pos(256, 0)); + } + + writebyte(offset, data); +} + + +//------------------------------------------------- +// draw_line_mode4 - draw mode 4 line +//------------------------------------------------- + +void zx8301_device::draw_line_mode4(bitmap_rgb32 &bitmap, int y, UINT16 da) +{ + int x = 0; + + for (int word = 0; word < 64; word++) + { + UINT8 byte_high = readbyte(da++); + UINT8 byte_low = readbyte(da++); + + for (int pixel = 0; pixel < 8; pixel++) + { + int red = BIT(byte_low, 7); + int green = BIT(byte_high, 7); + int color = (green << 1) | red; + + bitmap.pix32(y, x++) = PALETTE_ZX8301[ZX8301_COLOR_MODE4[color]]; + + byte_high <<= 1; + byte_low <<= 1; + } + } +} + + +//------------------------------------------------- +// draw_line_mode8 - draw mode 8 line +//------------------------------------------------- + +void zx8301_device::draw_line_mode8(bitmap_rgb32 &bitmap, int y, UINT16 da) +{ + int x = 0; + + for (int word = 0; word < 64; word++) + { + UINT8 byte_high = readbyte(da++); + UINT8 byte_low = readbyte(da++); + + for (int pixel = 0; pixel < 4; pixel++) + { + int red = BIT(byte_low, 7); + int green = BIT(byte_high, 7); + int blue = BIT(byte_low, 6); + int flash = BIT(byte_high, 6); + + int color = (green << 2) | (red << 1) | blue; + + if (flash && m_flash) + { + color = 0; + } + + bitmap.pix32(y, x++) = PALETTE_ZX8301[color]; + bitmap.pix32(y, x++) = PALETTE_ZX8301[color]; + + byte_high <<= 2; + byte_low <<= 2; + } + } +} + + +//------------------------------------------------- +// screen_update - +//------------------------------------------------- + +UINT32 zx8301_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + if (!m_dispoff) + { + UINT32 da = m_base << 15; + + for (int y = 0; y < 256; y++) + { + if (m_mode8) + { + draw_line_mode8(bitmap, y, da); + } + else + { + draw_line_mode4(bitmap, y, da); + } + + da += 128; + } + } + else + { + bitmap.fill(rgb_t::black, cliprect); + } + + return 0; +} |