summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/video/crt9007.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/video/crt9007.cpp')
-rw-r--r--src/devices/video/crt9007.cpp935
1 files changed, 935 insertions, 0 deletions
diff --git a/src/devices/video/crt9007.cpp b/src/devices/video/crt9007.cpp
new file mode 100644
index 00000000000..a5722fbd3bf
--- /dev/null
+++ b/src/devices/video/crt9007.cpp
@@ -0,0 +1,935 @@
+// license:BSD-3-Clause
+// copyright-holders:Curt Coder
+/**********************************************************************
+
+ SMC CRT9007 CRT Video Processor and Controller (VPAC) emulation
+
+**********************************************************************/
+
+/*
+
+ TODO:
+
+ - cursor timer
+ - interrupts
+ - light pen
+ - frame timer
+ - non-DMA mode
+ - DMA mode
+ - cursor/blank skew
+ - sequential breaks
+ - interlaced mode
+ - smooth scroll
+ - page blank
+ - double height cursor
+ - row attributes
+ - pin configuration
+ - operation modes 0,4,7
+ - address modes 1,2,3
+ - light pen
+ - state saving
+
+*/
+
+#include "emu.h"
+#include "crt9007.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type CRT9007 = &device_creator<crt9007_t>;
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define LOG 0
+
+#define HAS_VALID_PARAMETERS \
+ (m_reg[0x00] && m_reg[0x01] && m_reg[0x07] && m_reg[0x08] && m_reg[0x09])
+
+#define CHARACTERS_PER_HORIZONTAL_PERIOD \
+ m_reg[0x00]
+
+#define CHARACTERS_PER_DATA_ROW \
+ (m_reg[0x01] + 1)
+
+#define HORIZONTAL_DELAY \
+ m_reg[0x02]
+
+#define HORIZONTAL_SYNC_WIDTH \
+ m_reg[0x03]
+
+#define VERTICAL_SYNC_WIDTH \
+ m_reg[0x04]
+
+#define VERTICAL_DELAY \
+ (m_reg[0x05] - 1)
+
+#define PIN_CONFIGURATION \
+ (m_reg[0x06] >> 6)
+
+#define CURSOR_SKEW \
+ ((m_reg[0x06] >> 3) & 0x07)
+
+#define BLANK_SKEW \
+ (m_reg[0x06] & 0x07)
+
+#define VISIBLE_DATA_ROWS_PER_FRAME \
+ (m_reg[0x07] + 1)
+
+#define SCAN_LINES_PER_DATA_ROW \
+ ((m_reg[0x08] & 0x1f) + 1)
+
+#define SCAN_LINES_PER_FRAME \
+ (((m_reg[0x08] << 3) & 0x0700) | m_reg[0x09])
+
+#define DMA_BURST_COUNT \
+ ((m_reg[0x0a] & 0x0f) + 1)
+
+#define DMA_BURST_DELAY \
+ ((((m_reg[0x0a] >> 4) & 0x07) + 1) % 8)
+
+#define DMA_DISABLE \
+ BIT(m_reg[0x0a], 7)
+
+#define SINGLE_HEIGHT_CURSOR \
+ BIT(m_reg[0x0b], 0)
+
+#define OPERATION_MODE \
+ ((m_reg[0x0b] >> 1) & 0x07)
+
+#define INTERLACE_MODE \
+ ((m_reg[0x0b] >> 4) & 0x03)
+
+#define PAGE_BLANK \
+ BIT(m_reg[0x0b], 6)
+
+#define TABLE_START \
+ (((m_reg[0x0d] << 8) & 0x3f00) | m_reg[0x0c])
+
+#define ADDRESS_MODE \
+ ((m_reg[0x0d] >> 6) & 0x03)
+
+#define AUXILIARY_ADDRESS_1 \
+ (((m_reg[0x0f] << 8) & 0x3f00) | m_reg[0x0e])
+
+#define ROW_ATTRIBUTES_1 \
+ ((m_reg[0x0f] >> 6) & 0x03)
+
+#define SEQUENTIAL_BREAK_1 \
+ m_reg[0x10]
+
+#define SEQUENTIAL_BREAK_2 \
+ m_reg[0x12]
+
+#define DATA_ROW_START \
+ m_reg[0x11]
+
+#define DATA_ROW_END \
+ m_reg[0x12]
+
+#define AUXILIARY_ADDRESS_2 \
+ (((m_reg[0x14] << 8) & 0x3f00) | m_reg[0x13])
+
+#define ROW_ATTRIBUTES_2 \
+ ((m_reg[0x14] >> 6) & 0x03)
+
+#define SMOOTH_SCROLL_OFFSET \
+ ((m_reg[0x17] >> 1) & 0x3f)
+
+#define SMOOTH_SCROLL_OFFSET_OVERFLOW \
+ BIT(m_reg[0x17], 7)
+
+#define VERTICAL_CURSOR \
+ m_reg[0x18]
+
+#define HORIZONTAL_CURSOR \
+ m_reg[0x19]
+
+#define INTERRUPT_ENABLE \
+ m_reg[0x1a]
+
+#define FRAME_TIMER \
+ BIT(m_reg[0x1a], 0)
+
+#define LIGHT_PEN_INTERRUPT \
+ BIT(m_reg[0x1a], 5)
+
+#define VERTICAL_RETRACE_INTERRUPT \
+ BIT(m_reg[0x1a], 6)
+
+#define VERTICAL_LIGHT_PEN \
+ m_reg[0x3b]
+
+#define HORIZONTAL_LIGHT_PEN \
+ m_reg[0x3c]
+
+
+// interlace
+enum
+{
+ NON_INTERLACED = 0,
+ ENHANCED_VIDEO_INTERFACE,
+ NORMAL_VIDEO_INTERFACE
+};
+
+
+// operation modes
+enum
+{
+ OPERATION_MODE_REPETITIVE_MEMORY_ADDRESSING = 0, // not implemented
+ OPERATION_MODE_DOUBLE_ROW_BUFFER = 1,
+ OPERATION_MODE_SINGLE_ROW_BUFFER = 4, // not implemented
+ OPERATION_MODE_ATTRIBUTE_ASSEMBLE = 7 // not implemented
+};
+
+
+// addressing modes
+enum
+{
+ ADDRESS_MODE_SEQUENTIAL_ADDRESSING = 0,
+ ADDRESS_MODE_SEQUENTIAL_ROLL_ADDRESSING, // not implemented
+ ADDRESS_MODE_CONTIGUOUS_ROW_TABLE, // not implemented
+ ADDRESS_MODE_LINKED_LIST_ROW_TABLE // not implemented
+};
+
+
+// interrupt enable register bits
+const int IE_VERTICAL_RETRACE = 0x40;
+//const int IE_LIGHT_PEN = 0x20;
+//const int IE_FRAME_TIMER = 0x01;
+
+// status register bits
+const int STATUS_INTERRUPT_PENDING = 0x80;
+//const int STATUS_VERTICAL_RETRACE = 0x40;
+const int STATUS_LIGHT_PEN_UPDATE = 0x20;
+//const int STATUS_ODD_EVEN = 0x04;
+//const int STATUS_FRAME_TIMER_OCCURRED = 0x01;
+
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+// default address map
+static ADDRESS_MAP_START( crt9007, AS_0, 8, crt9007_t )
+ AM_RANGE(0x0000, 0x3fff) AM_RAM
+ADDRESS_MAP_END
+
+
+
+//**************************************************************************
+// INLINE HELPERS
+//**************************************************************************
+
+//-------------------------------------------------
+// readbyte - read a byte at the given address
+//-------------------------------------------------
+
+inline UINT8 crt9007_t::readbyte(offs_t address)
+{
+ return space().read_byte(address);
+}
+
+
+//-------------------------------------------------
+// trigger_interrupt -
+//-------------------------------------------------
+
+inline void crt9007_t::trigger_interrupt(int line)
+{
+ if (INTERRUPT_ENABLE & line)
+ {
+ int status = m_status;
+
+ m_status |= STATUS_INTERRUPT_PENDING | line;
+
+ if (!(status & STATUS_INTERRUPT_PENDING))
+ {
+ if (LOG) logerror("CRT9007 '%s' INT 1\n", tag());
+ m_write_int(ASSERT_LINE);
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// update_cblank_line -
+//-------------------------------------------------
+
+inline void crt9007_t::update_cblank_line()
+{
+ int x = m_screen->hpos();
+ int y = m_screen->vpos();
+
+ // composite blank
+ int cblank = !(m_hs & m_vs);
+
+ if (m_cblank != cblank)
+ {
+ m_cblank = cblank;
+
+ if (LOG) logerror("CRT9007 '%s' y %03u x %04u : CBLANK %u\n", tag(), y, x, m_cblank);
+
+ m_write_cblank(m_cblank);
+ }
+}
+
+
+//-------------------------------------------------
+// update_hsync_timer -
+//-------------------------------------------------
+
+inline void crt9007_t::update_hsync_timer(int state)
+{
+ int y = m_screen->vpos();
+
+ int next_x = state ? m_hsync_start : m_hsync_end;
+ int next_y = state ? (y + 1) % SCAN_LINES_PER_FRAME : y;
+
+ attotime duration = m_screen->time_until_pos(next_y, next_x);
+
+ m_hsync_timer->adjust(duration, !state);
+}
+
+
+//-------------------------------------------------
+// update_vsync_timer -
+//-------------------------------------------------
+
+inline void crt9007_t::update_vsync_timer(int state)
+{
+ int next_y = state ? m_vsync_start : m_vsync_end;
+
+ attotime duration = m_screen->time_until_pos(next_y, 0);
+
+ m_vsync_timer->adjust(duration, !state);
+}
+
+
+//-------------------------------------------------
+// update_vlt_timer -
+//-------------------------------------------------
+
+inline void crt9007_t::update_vlt_timer(int state)
+{
+ // this signal is active during all visible scan lines and during the horizontal trace at vertical retrace
+ int y = m_screen->vpos();
+
+ int next_x = state ? m_vlt_end : m_vlt_start;
+ int next_y = state ? y : ((y == m_vlt_bottom) ? 0 : (y + 1));
+
+ attotime duration = m_screen->time_until_pos(next_y, next_x);
+
+ m_vlt_timer->adjust(duration, !state);
+}
+
+
+//-------------------------------------------------
+// update_curs_timer -
+//-------------------------------------------------
+
+inline void crt9007_t::update_curs_timer(int state)
+{
+ // this signal is active for 1 character time for all scanlines within the data row
+ // TODO
+}
+
+
+//-------------------------------------------------
+// update_drb_timer -
+//-------------------------------------------------
+
+inline void crt9007_t::update_drb_timer(int state)
+{
+ // this signal is active for 1 full scan line (VLT edge to edge) at the top scan line of each new row
+ // there is 1 extra DRB signal during the 1st scanline of the vertical retrace interval
+ int y = m_screen->vpos();
+
+ int next_x = m_vlt_end;
+ int next_y = y ? y + 1 : y;
+
+ if (state)
+ {
+ if (y == 0)
+ {
+ next_y = VERTICAL_DELAY - 1;
+ }
+ else if (y == m_drb_bottom)
+ {
+ next_x = 0;
+ next_y = 0;
+ }
+ else
+ {
+ next_y = y + SCAN_LINES_PER_DATA_ROW - 1;
+ }
+ }
+
+ attotime duration = m_screen->time_until_pos(next_y, next_x);
+
+ m_drb_timer->adjust(duration, !state);
+}
+
+
+//-------------------------------------------------
+// update_dma_timer -
+//-------------------------------------------------
+
+inline void crt9007_t::update_dma_timer()
+{
+ // TODO
+}
+
+
+//-------------------------------------------------
+// recompute_parameters -
+//-------------------------------------------------
+
+inline void crt9007_t::recompute_parameters()
+{
+ // check that necessary registers have been loaded
+ if (!HAS_VALID_PARAMETERS) return;
+
+ // screen dimensions
+ //int horiz_pix_total = CHARACTERS_PER_HORIZONTAL_PERIOD * m_hpixels_per_column;
+ //int vert_pix_total = SCAN_LINES_PER_FRAME;
+
+ // refresh rate
+ //attoseconds_t refresh = HZ_TO_ATTOSECONDS(clock()) * horiz_pix_total * vert_pix_total;
+
+ // horizontal sync
+ m_hsync_start = 0;
+ m_hsync_end = HORIZONTAL_SYNC_WIDTH * m_hpixels_per_column;
+
+ // visible line time
+ m_vlt_start = HORIZONTAL_DELAY * m_hpixels_per_column;
+ m_vlt_end = (HORIZONTAL_DELAY + CHARACTERS_PER_DATA_ROW) * m_hpixels_per_column;
+ m_vlt_bottom = VERTICAL_DELAY + (VISIBLE_DATA_ROWS_PER_FRAME * SCAN_LINES_PER_DATA_ROW) - 1;
+
+ // data row boundary
+ m_drb_bottom = VERTICAL_DELAY + (VISIBLE_DATA_ROWS_PER_FRAME * SCAN_LINES_PER_DATA_ROW) - SCAN_LINES_PER_DATA_ROW;
+
+ // vertical sync
+ m_vsync_start = 0;
+ m_vsync_end = VERTICAL_SYNC_WIDTH;
+
+ // visible area
+ //rectangle visarea;
+
+ //visarea.set(m_hsync_end, horiz_pix_total - 1, m_vsync_end, vert_pix_total - 1);
+
+ //if (LOG)
+ //{
+ // logerror("CRT9007 '%s' Screen: %u x %u @ %f Hz\n", tag(), horiz_pix_total, vert_pix_total, 1 / ATTOSECONDS_TO_DOUBLE(refresh));
+ // logerror("CRT9007 '%s' Visible Area: (%u, %u) - (%u, %u)\n", tag(), visarea.min_x, visarea.min_y, visarea.max_x, visarea.max_y);
+ //}
+
+ //m_screen->configure(horiz_pix_total, vert_pix_total, visarea, refresh);
+
+ m_hsync_timer->adjust(m_screen->time_until_pos(0, 0));
+ m_vsync_timer->adjust(m_screen->time_until_pos(0, 0));
+ m_vlt_timer->adjust(m_screen->time_until_pos(0, m_vlt_start), 1);
+ m_drb_timer->adjust(m_screen->time_until_pos(0, 0));
+}
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// crt9007_t - constructor
+//-------------------------------------------------
+
+crt9007_t::crt9007_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, CRT9007, "SMC CRT9007", tag, owner, clock, "crt9007", __FILE__),
+ device_memory_interface(mconfig, *this),
+ device_video_interface(mconfig, *this),
+ m_space_config("videoram", ENDIANNESS_LITTLE, 8, 14, 0, NULL, *ADDRESS_MAP_NAME(crt9007)),
+ m_write_int(*this),
+ m_write_dmar(*this),
+ m_write_hs(*this),
+ m_write_vs(*this),
+ m_write_vlt(*this),
+ m_write_curs(*this),
+ m_write_drb(*this),
+ m_write_wben(*this),
+ m_write_cblank(*this),
+ m_write_slg(*this),
+ m_write_sld(*this)
+{
+ for (int i = 0; i < 0x3d; i++)
+ m_reg[i] = 0;
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void crt9007_t::device_start()
+{
+ // allocate timers
+ m_hsync_timer = timer_alloc(TIMER_HSYNC);
+ m_vsync_timer = timer_alloc(TIMER_VSYNC);
+ m_vlt_timer = timer_alloc(TIMER_VLT);
+ m_curs_timer = timer_alloc(TIMER_CURS);
+ m_drb_timer = timer_alloc(TIMER_DRB);
+ m_dma_timer = timer_alloc(TIMER_DMA);
+
+ // resolve callbacks
+ m_write_int.resolve_safe();
+ m_write_dmar.resolve_safe();
+ m_write_hs.resolve_safe();
+ m_write_vs.resolve_safe();
+ m_write_vlt.resolve_safe();
+ m_write_curs.resolve_safe();
+ m_write_drb.resolve_safe();
+ m_write_wben.resolve_safe();
+ m_write_cblank.resolve_safe();
+ m_write_slg.resolve_safe();
+ m_write_sld.resolve_safe();
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void crt9007_t::device_reset()
+{
+ m_disp = 0;
+ m_vs = 0;
+ m_cblank = 0;
+
+ // HS = 1
+ m_write_hs(1);
+
+ // VS = 1
+ m_write_vs(1);
+
+ // CBLANK = 1
+ m_write_cblank(0);
+
+ // CURS = 0
+ m_write_curs(0);
+
+ // VLT = 0
+ m_write_vlt(0);
+
+ // DRB = 1
+ m_write_drb(1);
+
+ // INT = 0
+ m_write_int(CLEAR_LINE);
+
+ // 28 (DMAR) = 0
+ m_write_dmar(CLEAR_LINE);
+
+ // 29 (WBEN) = 0
+ m_write_wben(1); // HACK
+
+ // 30 (SLG) = 0
+ m_write_slg(0);
+
+ // 31 (SLD) = 0
+ m_write_sld(0);
+
+ // 32 (LPSTB) = 0
+}
+
+
+//-------------------------------------------------
+// device_clock_changed - handle clock change
+//-------------------------------------------------
+
+void crt9007_t::device_clock_changed()
+{
+ recompute_parameters();
+}
+
+
+//-------------------------------------------------
+// device_timer - handle timer events
+//-------------------------------------------------
+
+void crt9007_t::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ int x = m_screen->hpos();
+ int y = m_screen->vpos();
+
+ switch (id)
+ {
+ case TIMER_HSYNC:
+ m_hs = param;
+
+ if (LOG) logerror("CRT9007 '%s' y %03u x %04u : HS %u\n", tag(), y, x, m_hs);
+
+ m_write_hs(m_hs);
+
+ update_cblank_line();
+
+ update_hsync_timer(param);
+ break;
+
+ case TIMER_VSYNC:
+ m_vs = param;
+
+ if (LOG) logerror("CRT9007 '%s' y %03u x %04u : VS %u\n", tag(), y, x, m_vs);
+
+ m_write_vs(param);
+
+ if (m_vs)
+ {
+ // reset all other bits except Light Pen Update to logic 0
+ m_status &= STATUS_LIGHT_PEN_UPDATE;
+ }
+ else
+ {
+ trigger_interrupt(IE_VERTICAL_RETRACE);
+
+ update_cblank_line();
+ }
+
+ update_vsync_timer(param);
+ break;
+
+ case TIMER_VLT:
+ m_vlt = param;
+
+ if (LOG) logerror("CRT9007 '%s' y %03u x %04u : VLT %u\n", tag(), y, x, m_vlt);
+
+ m_write_vlt(param);
+
+ update_vlt_timer(param);
+ break;
+
+ case TIMER_CURS:
+ if (LOG) logerror("CRT9007 '%s' y %03u x %04u : CURS %u\n", tag(), y, x, param);
+
+ m_write_curs(param);
+
+ update_curs_timer(param);
+ break;
+
+ case TIMER_DRB:
+ m_drb = param;
+
+ if (LOG) logerror("CRT9007 '%s' y %03u x %04u : DRB %u\n", tag(), y, x, m_drb);
+
+ m_write_drb(param);
+
+ if (!m_drb && !DMA_DISABLE)
+ {
+ // start DMA burst sequence
+ m_dma_count = CHARACTERS_PER_DATA_ROW;
+ m_dma_burst = DMA_BURST_COUNT ? (DMA_BURST_COUNT * 4) : CHARACTERS_PER_DATA_ROW;
+ m_dma_delay = DMA_BURST_DELAY;
+ m_dmar = 1;
+
+ if (LOG) logerror("CRT9007 '%s' DMAR 1\n", tag());
+ m_write_dmar(ASSERT_LINE);
+ }
+
+ update_drb_timer(param);
+ break;
+
+ case TIMER_DMA:
+ readbyte(AUXILIARY_ADDRESS_2);
+
+ update_dma_timer();
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// memory_space_config - return a description of
+// any address spaces owned by this device
+//-------------------------------------------------
+
+const address_space_config *crt9007_t::memory_space_config(address_spacenum spacenum) const
+{
+ return (spacenum == AS_0) ? &m_space_config : NULL;
+}
+
+
+//-------------------------------------------------
+// read - register read
+//-------------------------------------------------
+
+READ8_MEMBER( crt9007_t::read )
+{
+ UINT8 data = 0;
+
+ switch (offset)
+ {
+ case 0x15:
+ if (LOG) logerror("CRT9007 '%s' Start\n", tag());
+ m_disp = 1;
+ break;
+
+ case 0x16:
+ if (LOG) logerror("CRT9007 '%s' Reset\n", tag());
+ device_reset();
+ break;
+
+ case 0x38:
+ data = VERTICAL_CURSOR;
+ break;
+
+ case 0x39:
+ data = HORIZONTAL_CURSOR;
+ break;
+
+ case 0x3a:
+ data = m_status;
+
+ // reset interrupt pending bit
+ m_status &= ~STATUS_INTERRUPT_PENDING;
+ if (LOG) logerror("CRT9007 '%s' INT 0\n", tag());
+ m_write_int(CLEAR_LINE);
+ break;
+
+ case 0x3b:
+ data = VERTICAL_LIGHT_PEN;
+ break;
+
+ case 0x3c:
+ data = HORIZONTAL_LIGHT_PEN;
+
+ // reset light pen update bit
+ m_status &= ~STATUS_LIGHT_PEN_UPDATE;
+ break;
+
+ default:
+ logerror("CRT9007 '%s' Read from Invalid Register: %02x!\n", tag(), offset);
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// write - register write
+//-------------------------------------------------
+
+WRITE8_MEMBER( crt9007_t::write )
+{
+ m_reg[offset] = data;
+
+ switch (offset)
+ {
+ case 0x00:
+ recompute_parameters();
+ if (LOG) logerror("CRT9007 '%s' Characters per Horizontal Period: %u\n", tag(), CHARACTERS_PER_HORIZONTAL_PERIOD);
+ break;
+
+ case 0x01:
+ recompute_parameters();
+ if (LOG) logerror("CRT9007 '%s' Characters per Data Row: %u\n", tag(), CHARACTERS_PER_DATA_ROW);
+ break;
+
+ case 0x02:
+ recompute_parameters();
+ if (LOG) logerror("CRT9007 '%s' Horizontal Delay: %u\n", tag(), HORIZONTAL_DELAY);
+ break;
+
+ case 0x03:
+ recompute_parameters();
+ if (LOG) logerror("CRT9007 '%s' Horizontal Sync Width: %u\n", tag(), HORIZONTAL_SYNC_WIDTH);
+ break;
+
+ case 0x04:
+ recompute_parameters();
+ if (LOG) logerror("CRT9007 '%s' Vertical Sync Width: %u\n", tag(), VERTICAL_SYNC_WIDTH);
+ break;
+
+ case 0x05:
+ recompute_parameters();
+ if (LOG) logerror("CRT9007 '%s' Vertical Delay: %u\n", tag(), VERTICAL_DELAY);
+ break;
+
+ case 0x06:
+ recompute_parameters();
+ if (LOG)
+ {
+ logerror("CRT9007 '%s' Pin Configuration: %u\n", tag(), PIN_CONFIGURATION);
+ logerror("CRT9007 '%s' Cursor Skew: %u\n", tag(), CURSOR_SKEW);
+ logerror("CRT9007 '%s' Blank Skew: %u\n", tag(), BLANK_SKEW);
+ }
+ break;
+
+ case 0x07:
+ recompute_parameters();
+ if (LOG) logerror("CRT9007 '%s' Visible Data Rows per Frame: %u\n", tag(), VISIBLE_DATA_ROWS_PER_FRAME);
+ break;
+
+ case 0x08:
+ recompute_parameters();
+ if (LOG) logerror("CRT9007 '%s' Scan Lines per Data Row: %u\n", tag(), SCAN_LINES_PER_DATA_ROW);
+ break;
+
+ case 0x09:
+ recompute_parameters();
+ if (LOG) logerror("CRT9007 '%s' Scan Lines per Frame: %u\n", tag(), SCAN_LINES_PER_FRAME);
+ break;
+
+ case 0x0a:
+ if (LOG)
+ {
+ logerror("CRT9007 '%s' DMA Burst Count: %u\n", tag(), DMA_BURST_COUNT);
+ logerror("CRT9007 '%s' DMA Burst Delay: %u\n", tag(), DMA_BURST_DELAY);
+ logerror("CRT9007 '%s' DMA Disable: %u\n", tag(), DMA_DISABLE);
+ }
+ break;
+
+ case 0x0b:
+ if (LOG)
+ {
+ logerror("CRT9007 '%s' %s Height Cursor\n", tag(), SINGLE_HEIGHT_CURSOR ? "Single" : "Double");
+ logerror("CRT9007 '%s' Operation Mode: %u\n", tag(), OPERATION_MODE);
+ logerror("CRT9007 '%s' Interlace Mode: %u\n", tag(), INTERLACE_MODE);
+ logerror("CRT9007 '%s' %s Mechanism\n", tag(), PAGE_BLANK ? "Page Blank" : "Smooth Scroll");
+ }
+ break;
+
+ case 0x0c:
+ break;
+
+ case 0x0d:
+ if (LOG)
+ {
+ logerror("CRT9007 '%s' Table Start Register: %04x\n", tag(), TABLE_START);
+ logerror("CRT9007 '%s' Address Mode: %u\n", tag(), ADDRESS_MODE);
+ }
+ break;
+
+ case 0x0e:
+ break;
+
+ case 0x0f:
+ if (LOG)
+ {
+ logerror("CRT9007 '%s' Auxialiary Address Register 1: %04x\n", tag(), AUXILIARY_ADDRESS_1);
+ logerror("CRT9007 '%s' Row Attributes: %u\n", tag(), ROW_ATTRIBUTES_1);
+ }
+ break;
+
+ case 0x10:
+ if (LOG) logerror("CRT9007 '%s' Sequential Break Register 1: %u\n", tag(), SEQUENTIAL_BREAK_1);
+ break;
+
+ case 0x11:
+ if (LOG) logerror("CRT9007 '%s' Data Row Start Register: %u\n", tag(), DATA_ROW_START);
+ break;
+
+ case 0x12:
+ if (LOG) logerror("CRT9007 '%s' Data Row End/Sequential Break Register 2: %u\n", tag(), SEQUENTIAL_BREAK_2);
+ break;
+
+ case 0x13:
+ break;
+
+ case 0x14:
+ if (LOG)
+ {
+ logerror("CRT9007 '%s' Auxiliary Address Register 2: %04x\n", tag(), AUXILIARY_ADDRESS_2);
+ logerror("CRT9007 '%s' Row Attributes: %u\n", tag(), ROW_ATTRIBUTES_2);
+ }
+ break;
+
+ case 0x15:
+ if (LOG) logerror("CRT9007 '%s' Start\n", tag());
+ m_disp = 1;
+ break;
+
+ case 0x16:
+ if (LOG) logerror("CRT9007 '%s' Reset\n", tag());
+ device_reset();
+ break;
+
+ case 0x17:
+ if (LOG)
+ {
+ logerror("CRT9007 '%s' Smooth Scroll Offset: %u\n", tag(), SMOOTH_SCROLL_OFFSET);
+ logerror("CRT9007 '%s' Smooth Scroll Offset Overflow: %u\n", tag(), SMOOTH_SCROLL_OFFSET_OVERFLOW);
+ }
+ break;
+
+ case 0x18:
+ if (LOG) logerror("CRT9007 '%s' Vertical Cursor Register: %u\n", tag(), VERTICAL_CURSOR);
+ break;
+
+ case 0x19:
+ if (LOG) logerror("CRT9007 '%s' Horizontal Cursor Register: %u\n", tag(), HORIZONTAL_CURSOR);
+ break;
+
+ case 0x1a:
+ if (LOG)
+ {
+ logerror("CRT9007 '%s' Frame Timer: %u\n", tag(), FRAME_TIMER);
+ logerror("CRT9007 '%s' Light Pen Interrupt: %u\n", tag(), LIGHT_PEN_INTERRUPT);
+ logerror("CRT9007 '%s' Vertical Retrace Interrupt: %u\n", tag(), VERTICAL_RETRACE_INTERRUPT);
+ }
+ break;
+
+ default:
+ logerror("CRT9007 '%s' Write to Invalid Register: %02x!\n", tag(), offset);
+ }
+}
+
+
+//-------------------------------------------------
+// ack_w - DMA acknowledge
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( crt9007_t::ack_w )
+{
+ if (LOG) logerror("CRT9007 '%s' ACK: %u\n", tag(), state);
+
+ if (m_dmar && !m_ack && state)
+ {
+ // start DMA transfer
+ m_dma_timer->adjust(attotime::from_hz(clock()));
+ }
+
+ m_ack = state;
+}
+
+
+//-------------------------------------------------
+// lpstb_w - light pen strobe
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( crt9007_t::lpstb_w )
+{
+ if (LOG) logerror("CRT9007 '%s' LPSTB: %u\n", tag(), state);
+
+ if (!m_lpstb && state)
+ {
+ // TODO latch current row/column position
+ }
+
+ m_lpstb = state;
+}
+
+
+//-------------------------------------------------
+// set_character_width -
+//-------------------------------------------------
+
+void crt9007_t::set_character_width(int value)
+{
+ m_hpixels_per_column = value;
+
+ recompute_parameters();
+}