mirror of
https://github.com/holub/mame
synced 2025-04-25 09:50:04 +03:00
dp8350: More complete line-by-line emulation of timing outputs (nw)
This commit is contained in:
parent
ceb6c25436
commit
c920ea8593
@ -5,11 +5,20 @@
|
||||
National Semiconductor DP8350 Series CRT Controllers
|
||||
|
||||
These dedicated CRTC devices are “programmable” by specifying a
|
||||
long list of mask parameters. The number of parameters adjustable
|
||||
through software is relatively small, there being no dedicated
|
||||
microprocessor data bus. In practice, however, the CPU's D0 and
|
||||
D1 are usually tied to the Register Select lines, due to shared
|
||||
use of the address bus for DMA purposes.
|
||||
long list of mask parameters. Since the dot clock is generated
|
||||
internally, these parameters determine the character field size
|
||||
(16 x 16 maximum) as well as the number of characters displayed
|
||||
on screen and the timing, width and polarity of the sync pulses
|
||||
(though two different vertical timings are incorporated so the
|
||||
refresh rate can be switched between 60 Hz and 50 Hz).
|
||||
|
||||
The number of parameters adjustable through software control is
|
||||
relatively small, there being no dedicated microprocessor data bus.
|
||||
In practice, however, the CPU's D0 and D1 are usually tied to the
|
||||
Register Select lines, due to shared use of the address bus for
|
||||
DMA purposes. A per-row interrupt can be derived in various ways
|
||||
from the timing outputs; this can be used to reload the Row Start
|
||||
Register to point to display memory at nonconsecutive addresses.
|
||||
|
||||
National released the DP8350 and a few other standard versions.
|
||||
DP8367 appears to have originally been a custom mask variant
|
||||
@ -17,7 +26,9 @@
|
||||
later datasheets; its parameters have been derived from the
|
||||
information presented in Manual Part No. 13220-91087. (The 8367
|
||||
designation also comes from there, since the actual IC is merely
|
||||
marked with its HP part number, 1820-2373.)
|
||||
marked with its HP part number, 1820-2373.) DP8369 is another
|
||||
variant ordered by General Terminal Corp. for their SW10 terminal;
|
||||
option “K” is its National designation.
|
||||
|
||||
Variant Dot rate Monitor type
|
||||
------- -------- ------------
|
||||
@ -25,6 +36,7 @@
|
||||
DP8352 7.02 MHz RS-170 compatible
|
||||
DP8353 17.6256 MHz Motorola M3003
|
||||
DP8367 25.7715 MHz HP 13220
|
||||
DP8369 12.2472 MHz GTC SW10
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
@ -76,12 +88,27 @@ dp835x_device::dp835x_device(const machine_config &mconfig, device_type type, co
|
||||
, m_hsync_active(hsync_active)
|
||||
, m_vsync_active(vsync_active)
|
||||
, m_vblank_active(vblank_active)
|
||||
, m_dots_per_line(char_width * chars_per_line)
|
||||
, m_dots_per_row(char_width * chars_per_row)
|
||||
, m_video_scan_lines(char_height * rows_per_frame)
|
||||
, m_lrc_callback(*this)
|
||||
, m_clc_callback(*this)
|
||||
, m_lc_callback(*this)
|
||||
, m_lbre_callback(*this)
|
||||
, m_hsync_callback(*this)
|
||||
, m_vsync_callback(*this)
|
||||
, m_vblank_callback(*this)
|
||||
, m_60hz_refresh(true)
|
||||
, m_cgpi(false)
|
||||
, m_topr(0)
|
||||
, m_rsr(0)
|
||||
, m_cr(0)
|
||||
, m_row_start(0)
|
||||
, m_lc(0)
|
||||
{
|
||||
// some parameters are not used yet
|
||||
// some parameters are not used (at least not directly)
|
||||
(void)m_rows_per_frame;
|
||||
(void)m_chars_per_line;
|
||||
(void)m_cursor_on_all_lines;
|
||||
(void)m_lbc_0_width;
|
||||
(void)m_hsync_serration;
|
||||
@ -97,7 +124,7 @@ dp8350_device::dp8350_device(const machine_config &mconfig, const char *tag, dev
|
||||
7, 10, 80, 24,
|
||||
4, 10, 20,
|
||||
30, 10, 72,
|
||||
100, 0, 4, 1, // HSYNC width given in datasheet as an impossible 43 character times
|
||||
100, 0, 43, 1, // yes, the horizontal sync pulse is more than twice as long as the blanking period
|
||||
true, 4, 0,
|
||||
true, false, true)
|
||||
{
|
||||
@ -129,14 +156,11 @@ void dp835x_device::device_config_complete()
|
||||
{
|
||||
if (has_screen() && screen().refresh_attoseconds() == 0)
|
||||
{
|
||||
int dots_per_line = m_char_width * m_chars_per_line;
|
||||
int dots_per_row = m_char_width * m_chars_per_row;
|
||||
int lines_per_frame = m_char_height * m_rows_per_frame + m_vblank_interval[m_60hz_refresh ? 1 : 0];
|
||||
|
||||
int lines_per_frame = m_video_scan_lines + m_vblank_interval[m_60hz_refresh ? 1 : 0];
|
||||
if (m_half_shift)
|
||||
screen().set_raw(clock() * 2, dots_per_line * 2, 0, dots_per_row * 2, lines_per_frame, 0, m_char_height * m_rows_per_frame);
|
||||
screen().set_raw(clock() * 2, m_dots_per_line * 2, 0, m_dots_per_row * 2, lines_per_frame, 0, m_video_scan_lines);
|
||||
else
|
||||
screen().set_raw(clock(), dots_per_line, 0, dots_per_row, lines_per_frame, 0, m_char_height * m_rows_per_frame);
|
||||
screen().set_raw(clock(), m_dots_per_line, 0, m_dots_per_row, lines_per_frame, 0, m_video_scan_lines);
|
||||
}
|
||||
}
|
||||
|
||||
@ -149,6 +173,10 @@ void dp835x_device::device_config_complete()
|
||||
|
||||
void dp835x_device::device_resolve_objects()
|
||||
{
|
||||
m_lrc_callback.resolve_safe();
|
||||
m_clc_callback.resolve_safe();
|
||||
m_lc_callback.resolve_safe();
|
||||
m_lbre_callback.resolve_safe();
|
||||
m_hsync_callback.resolve_safe();
|
||||
m_vsync_callback.resolve_safe();
|
||||
m_vblank_callback.resolve_safe();
|
||||
@ -162,15 +190,19 @@ void dp835x_device::device_resolve_objects()
|
||||
void dp835x_device::device_start()
|
||||
{
|
||||
// create timers
|
||||
m_hblank_start_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(dp835x_device::hblank_start), this));
|
||||
m_hblank_near_end_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(dp835x_device::hblank_near_end), this));
|
||||
m_hsync_on_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(dp835x_device::hsync_update), this));
|
||||
m_hsync_off_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(dp835x_device::hsync_update), this));
|
||||
m_vsync_on_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(dp835x_device::vsync_update), this));
|
||||
m_vsync_off_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(dp835x_device::vsync_update), this));
|
||||
m_vblank_on_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(dp835x_device::vblank_update), this));
|
||||
m_vblank_off_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(dp835x_device::vblank_update), this));
|
||||
|
||||
// save state
|
||||
save_item(NAME(m_60hz_refresh));
|
||||
save_item(NAME(m_cgpi));
|
||||
save_item(NAME(m_lc));
|
||||
save_item(NAME(m_topr));
|
||||
save_item(NAME(m_rsr));
|
||||
save_item(NAME(m_cr));
|
||||
save_item(NAME(m_row_start));
|
||||
}
|
||||
|
||||
|
||||
@ -180,6 +212,10 @@ void dp835x_device::device_start()
|
||||
|
||||
void dp835x_device::device_reset()
|
||||
{
|
||||
m_topr = 0;
|
||||
m_rsr = 0;
|
||||
m_cr = 0;
|
||||
m_row_start = 0;
|
||||
}
|
||||
|
||||
|
||||
@ -200,70 +236,68 @@ void dp835x_device::device_clock_changed()
|
||||
|
||||
void dp835x_device::reconfigure_screen()
|
||||
{
|
||||
int dots_per_line = m_char_width * m_chars_per_line;
|
||||
int dots_per_row = m_char_width * m_chars_per_row;
|
||||
int lines_per_frame = m_char_height * m_rows_per_frame + m_vblank_interval[m_60hz_refresh ? 1 : 0];
|
||||
attotime refresh = clocks_to_attotime(lines_per_frame * dots_per_line);
|
||||
int lines_per_frame = m_video_scan_lines + m_vblank_interval[m_60hz_refresh ? 1 : 0];
|
||||
attotime scan_period = clocks_to_attotime(m_dots_per_line);
|
||||
attotime refresh = clocks_to_attotime(lines_per_frame * m_dots_per_line);
|
||||
|
||||
if (m_half_shift)
|
||||
{
|
||||
rectangle visarea(0, 2 * dots_per_row - 1, 0, m_char_height * m_rows_per_frame - 1);
|
||||
screen().configure(2 * dots_per_line, lines_per_frame, visarea, refresh.as_attoseconds());
|
||||
rectangle visarea(0, 2 * m_dots_per_row - 1, 0, m_video_scan_lines - 1);
|
||||
screen().configure(2 * m_dots_per_line, lines_per_frame, visarea, refresh.as_attoseconds());
|
||||
}
|
||||
else
|
||||
{
|
||||
rectangle visarea(0, dots_per_row - 1, 0, m_char_height * m_rows_per_frame - 1);
|
||||
screen().configure(dots_per_line, lines_per_frame, visarea, refresh.as_attoseconds());
|
||||
rectangle visarea(0, m_dots_per_row - 1, 0, m_video_scan_lines - 1);
|
||||
screen().configure(m_dots_per_line, lines_per_frame, visarea, refresh.as_attoseconds());
|
||||
}
|
||||
|
||||
logerror("Frame rate refresh: %.2f Hz (f%d); horizontal rate scan: %.4f kHz; character rate: %.4f MHz; dot rate: %.5f MHz\n",
|
||||
ATTOSECONDS_TO_HZ(refresh.as_attoseconds()),
|
||||
m_60hz_refresh ? 1 : 0,
|
||||
clock() / (dots_per_line * 1000.0),
|
||||
clock() / (m_dots_per_line * 1000.0),
|
||||
clock() / (m_char_width * 1000000.0),
|
||||
clock() / 1000000.0);
|
||||
|
||||
// get current screen position
|
||||
int hpos = screen().hpos();
|
||||
int vpos = screen().vpos();
|
||||
// get current screen position (note that this method is more accurate than calling hpos and vpos separately)
|
||||
u32 dpos = attotime_to_clocks(refresh - screen().time_until_pos(lines_per_frame - 1, m_dots_per_row * (m_half_shift ? 2 : 1)));
|
||||
int hpos = (dpos + m_dots_per_row) % m_dots_per_line;
|
||||
int vpos = dpos / m_dots_per_line;
|
||||
|
||||
// set horizontal sync timers
|
||||
int hsync_begin = (dots_per_row + m_char_width * m_hsync_delay) * (m_half_shift ? 2 : 1);
|
||||
int hsync_end = hsync_begin + m_char_width * m_hsync_width * (m_half_shift ? 2 : 1);
|
||||
if (hpos > hsync_begin)
|
||||
hsync_begin += dots_per_line * (m_half_shift ? 2 : 1);
|
||||
m_hsync_on_timer->adjust(clocks_to_attotime(hsync_begin - hpos) / (m_half_shift ? 2 : 1), m_hsync_active, clocks_to_attotime(dots_per_line));
|
||||
if (hpos > hsync_end)
|
||||
hsync_end += dots_per_line * (m_half_shift ? 2 : 1);
|
||||
m_hsync_off_timer->adjust(clocks_to_attotime(hsync_end - hpos) / (m_half_shift ? 2 : 1), !m_hsync_active, clocks_to_attotime(dots_per_line));
|
||||
// set line rate clock timers
|
||||
int hblank_begin = m_dots_per_row;
|
||||
int hblank_near_end = m_dots_per_line - m_char_width * 5;
|
||||
if (hpos >= hblank_begin)
|
||||
hblank_begin += m_dots_per_line;
|
||||
m_hblank_start_timer->adjust(clocks_to_attotime(hblank_begin - hpos), 0, scan_period);
|
||||
if (hpos >= hblank_near_end)
|
||||
hblank_near_end += m_dots_per_line;
|
||||
m_hblank_near_end_timer->adjust(clocks_to_attotime(hblank_near_end - hpos), 0, scan_period);
|
||||
|
||||
// set horizontal sync timers (note that HSYNC may precede horizontal blanking or even outlast it, as on the DP8350)
|
||||
int hsync_begin = m_dots_per_row + m_char_width * m_hsync_delay;
|
||||
int hsync_end = hsync_begin + m_char_width * m_hsync_width;
|
||||
if (hpos >= hsync_begin)
|
||||
hsync_begin += m_dots_per_line;
|
||||
m_hsync_on_timer->adjust(clocks_to_attotime(hsync_begin - hpos), m_hsync_active, scan_period);
|
||||
if (hpos >= hsync_end)
|
||||
hsync_end += m_dots_per_line;
|
||||
else if (hpos < hsync_end - m_dots_per_line)
|
||||
hsync_end -= m_dots_per_line;
|
||||
m_hsync_off_timer->adjust(clocks_to_attotime(hsync_end - hpos), !m_hsync_active, scan_period);
|
||||
logerror("hblank_begin: %d; hsync_begin: %d; hsync_end: %d; hpos: %d\n", hblank_begin, hsync_begin, hsync_end, hpos);
|
||||
|
||||
// calculate vertical sync and blanking parameters
|
||||
int hblank_begin = dots_per_row * (m_half_shift ? 2 : 1);
|
||||
int vblank_begin = m_char_height * m_rows_per_frame - 1;
|
||||
int vsync_begin = vblank_begin + m_vsync_delay[m_60hz_refresh ? 1 : 0];
|
||||
int vsync_begin = m_video_scan_lines + m_vsync_delay[m_60hz_refresh ? 1 : 0];
|
||||
int vsync_end = vsync_begin + m_vsync_width[m_60hz_refresh ? 1 : 0];
|
||||
int vblank_end = lines_per_frame - m_vblank_stop - 1;
|
||||
logerror("vblank_begin: %d; vsync_begin: %d; vsync_end: %d; vblank_end: %d; vpos: %d\n", vblank_begin, vsync_begin, vsync_end, vblank_end, vpos);
|
||||
if (hpos > hblank_begin)
|
||||
{
|
||||
hblank_begin += dots_per_line * (m_half_shift ? 2 : 1);
|
||||
vpos++;
|
||||
}
|
||||
attotime until_hblank = clocks_to_attotime(hblank_begin - hpos) / (m_half_shift ? 2 : 1);
|
||||
int vblank_end = lines_per_frame - m_vblank_stop;
|
||||
logerror("vblank_begin: %d; vsync_begin: %d; vsync_end: %d; vblank_end: %d; vpos: %d\n", m_video_scan_lines, vsync_begin, vsync_end, vblank_end, vpos);
|
||||
|
||||
// set vertical sync and blanking timers
|
||||
if (vpos > vsync_begin)
|
||||
vsync_begin += lines_per_frame;
|
||||
m_vsync_on_timer->adjust(clocks_to_attotime((vsync_begin - vpos) * dots_per_line) + until_hblank, m_vsync_active, refresh);
|
||||
if (vpos > vsync_end)
|
||||
vsync_end += lines_per_frame;
|
||||
m_vsync_off_timer->adjust(clocks_to_attotime((vsync_end - vpos) * dots_per_line) + until_hblank, !m_vsync_active, refresh);
|
||||
if (vpos > vblank_begin)
|
||||
vblank_begin += lines_per_frame;
|
||||
m_vblank_on_timer->adjust(clocks_to_attotime((vblank_begin - vpos) * dots_per_line) + until_hblank, m_vblank_active, refresh);
|
||||
if (vpos > vblank_end)
|
||||
vblank_end += lines_per_frame;
|
||||
m_vblank_off_timer->adjust(clocks_to_attotime((vblank_end - vpos) * dots_per_line) + until_hblank, !m_vblank_active, refresh);
|
||||
// set counters
|
||||
m_line = vpos;
|
||||
if (m_line >= lines_per_frame - m_char_height)
|
||||
m_lc = m_line - (lines_per_frame - m_char_height);
|
||||
else
|
||||
m_lc = m_line % m_char_height;
|
||||
}
|
||||
|
||||
|
||||
@ -283,6 +317,21 @@ WRITE_LINE_MEMBER(dp835x_device::refresh_control)
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// character_generator_program - set or configure
|
||||
// the character generator program input (CGPI):
|
||||
// 0 = video begins on scan line 0; new addresses
|
||||
// loaded on last scan line of previous character
|
||||
// 1 = video begins on scan line 1; new addresses
|
||||
// loaded on scan line 0
|
||||
//-------------------------------------------------
|
||||
|
||||
WRITE_LINE_MEMBER(dp835x_device::character_generator_program)
|
||||
{
|
||||
m_cgpi = bool(state);
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// register_load - write to one of three CRTC
|
||||
// address registers
|
||||
@ -302,21 +351,45 @@ void dp835x_device::register_load(u8 rs, u16 addr)
|
||||
case 1:
|
||||
// A = 0, B = 1: Top-of-Page
|
||||
logerror("Top-of-Page Register = %03X\n", addr);
|
||||
m_topr = addr;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// A = 1, B = 0: Row Start (also Top-of-Page during vertical blanking)
|
||||
logerror("Row Start Register = %03X\n", addr);
|
||||
if (m_line >= m_video_scan_lines)
|
||||
{
|
||||
logerror("Row Start Register = %03X (redirected to Top-of-Page)\n", addr);
|
||||
m_topr = addr;
|
||||
}
|
||||
else
|
||||
{
|
||||
logerror("Row Start Register = %03X\n", addr);
|
||||
m_rsr = addr;
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
// A = 1, B = 1: Cursor
|
||||
logerror("Cursor Register = %03X\n", addr);
|
||||
m_cr = addr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// lrc_r - report line rate clock state
|
||||
//-------------------------------------------------
|
||||
|
||||
READ_LINE_MEMBER(dp835x_device::lrc_r)
|
||||
{
|
||||
if (m_hblank_start_timer->remaining() > m_hblank_near_end_timer->remaining())
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// hsync_r - report horizontal sync state
|
||||
//-------------------------------------------------
|
||||
@ -331,15 +404,14 @@ READ_LINE_MEMBER(dp835x_device::hsync_r)
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// vblank_r - report vertical sync state
|
||||
// vsync_r - report vertical sync state
|
||||
//-------------------------------------------------
|
||||
|
||||
READ_LINE_MEMBER(dp835x_device::vsync_r)
|
||||
{
|
||||
if (m_vsync_on_timer->remaining() > m_vsync_off_timer->remaining())
|
||||
return m_vsync_active;
|
||||
else
|
||||
return !m_vsync_active;
|
||||
int vsync_begin = m_video_scan_lines + m_vsync_delay[m_60hz_refresh ? 1 : 0];
|
||||
int vsync_end = vsync_begin + m_vsync_width[m_60hz_refresh ? 1 : 0];
|
||||
return (m_line >= vsync_begin && m_line < vsync_end) ? m_vsync_active : !m_vsync_active;
|
||||
}
|
||||
|
||||
|
||||
@ -349,10 +421,83 @@ READ_LINE_MEMBER(dp835x_device::vsync_r)
|
||||
|
||||
READ_LINE_MEMBER(dp835x_device::vblank_r)
|
||||
{
|
||||
if (m_vblank_on_timer->remaining() > m_vblank_off_timer->remaining())
|
||||
return m_vblank_active;
|
||||
int vblank_end = m_video_scan_lines + m_vblank_interval[m_60hz_refresh ? 1 : 0] - m_vblank_stop;
|
||||
return (m_line >= m_video_scan_lines && m_line < vblank_end) ? m_vblank_active : !m_vblank_active;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// hblank_start - update timing outputs at the
|
||||
// start of horizontal blanking
|
||||
//-------------------------------------------------
|
||||
|
||||
TIMER_CALLBACK_MEMBER(dp835x_device::hblank_start)
|
||||
{
|
||||
int lines_per_frame = m_video_scan_lines + m_vblank_interval[m_60hz_refresh ? 1 : 0];
|
||||
int vsync_begin = m_video_scan_lines + m_vsync_delay[m_60hz_refresh ? 1 : 0];
|
||||
int vsync_end = vsync_begin + m_vsync_width[m_60hz_refresh ? 1 : 0];
|
||||
int vblank_end = lines_per_frame - m_vblank_stop;
|
||||
|
||||
// falling edge of line rate clock
|
||||
m_lrc_callback(0);
|
||||
|
||||
// increment line counter or reset it
|
||||
if (m_lc < m_char_height - 1 && m_line != lines_per_frame - m_char_height)
|
||||
m_lc++;
|
||||
else
|
||||
return !m_vblank_active;
|
||||
{
|
||||
m_lc = 0;
|
||||
m_clc_callback(0);
|
||||
}
|
||||
m_lc_callback(m_lc);
|
||||
|
||||
// increment internal 9-bit scan counter
|
||||
m_line++;
|
||||
//assert(m_line == screen().vpos() + 1);
|
||||
|
||||
// update line buffer recirculate enable output based on address mode
|
||||
bool lbre = m_lc != (m_cgpi ? 0 : m_char_height - 1);
|
||||
m_lbre_callback(lbre ? 1 : 0);
|
||||
|
||||
if (m_line >= lines_per_frame - m_char_height && m_line < lines_per_frame)
|
||||
{
|
||||
m_row_start = m_rsr = m_topr;
|
||||
}
|
||||
else if (!lbre || m_line >= m_video_scan_lines)
|
||||
{
|
||||
// calculate starting address of next row (address counter runs continuously during VBLANK)
|
||||
m_row_start = m_rsr;
|
||||
m_rsr = (m_row_start + m_chars_per_row) & 0xfff;
|
||||
}
|
||||
|
||||
// update vertical blanking output
|
||||
if (m_line == m_video_scan_lines)
|
||||
m_vblank_callback(m_vblank_active);
|
||||
else if (m_line == vblank_end)
|
||||
m_vblank_callback(!m_vblank_active);
|
||||
|
||||
// update vertical sync output
|
||||
if (m_line == vsync_begin)
|
||||
m_vsync_callback(m_vsync_active);
|
||||
else if (m_line == vsync_end)
|
||||
m_vsync_callback(!m_vsync_active);
|
||||
|
||||
if (m_line == lines_per_frame)
|
||||
m_line = 0;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// hblank_near_end - update line rate outputs
|
||||
// five chars before horizontal blanking ends
|
||||
//-------------------------------------------------
|
||||
|
||||
TIMER_CALLBACK_MEMBER(dp835x_device::hblank_near_end)
|
||||
{
|
||||
// rising edge of line rate clock
|
||||
m_lrc_callback(1);
|
||||
if (m_lc == 0)
|
||||
m_clc_callback(1);
|
||||
}
|
||||
|
||||
|
||||
@ -365,25 +510,3 @@ TIMER_CALLBACK_MEMBER(dp835x_device::hsync_update)
|
||||
{
|
||||
m_hsync_callback(param);
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// vsync_update - update state of vertical
|
||||
// sync output
|
||||
//-------------------------------------------------
|
||||
|
||||
TIMER_CALLBACK_MEMBER(dp835x_device::vsync_update)
|
||||
{
|
||||
m_vsync_callback(param);
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// vblank_update - update state of vertical
|
||||
// blanking output
|
||||
//-------------------------------------------------
|
||||
|
||||
TIMER_CALLBACK_MEMBER(dp835x_device::vblank_update)
|
||||
{
|
||||
m_vblank_callback(param);
|
||||
}
|
||||
|
@ -44,6 +44,10 @@ class dp835x_device : public device_t, public device_video_interface
|
||||
{
|
||||
public:
|
||||
// device configuration
|
||||
auto lrc_callback() { return m_lrc_callback.bind(); }
|
||||
auto clc_callback() { return m_clc_callback.bind(); }
|
||||
auto lc_callback() { return m_lc_callback.bind(); }
|
||||
auto lbre_callback() { return m_lbre_callback.bind(); }
|
||||
auto hsync_callback() { return m_hsync_callback.bind(); }
|
||||
auto vsync_callback() { return m_vsync_callback.bind(); }
|
||||
auto vblank_callback() { return m_vblank_callback.bind(); }
|
||||
@ -51,9 +55,12 @@ public:
|
||||
|
||||
// write handlers
|
||||
DECLARE_WRITE_LINE_MEMBER(refresh_control);
|
||||
DECLARE_WRITE_LINE_MEMBER(character_generator_program);
|
||||
void register_load(u8 rs, u16 addr);
|
||||
|
||||
// read handlers
|
||||
DECLARE_READ_LINE_MEMBER(lrc_r);
|
||||
u8 lc_r() { return m_lc; }
|
||||
DECLARE_READ_LINE_MEMBER(hsync_r);
|
||||
DECLARE_READ_LINE_MEMBER(vsync_r);
|
||||
DECLARE_READ_LINE_MEMBER(vblank_r);
|
||||
@ -80,9 +87,9 @@ private:
|
||||
void reconfigure_screen();
|
||||
|
||||
// timer callbacks
|
||||
TIMER_CALLBACK_MEMBER(hblank_start);
|
||||
TIMER_CALLBACK_MEMBER(hblank_near_end);
|
||||
TIMER_CALLBACK_MEMBER(hsync_update);
|
||||
TIMER_CALLBACK_MEMBER(vsync_update);
|
||||
TIMER_CALLBACK_MEMBER(vblank_update);
|
||||
|
||||
// mask parameters
|
||||
const int m_char_width; // character field cell size (width in dots)
|
||||
@ -103,24 +110,40 @@ private:
|
||||
const bool m_vsync_active; // active level of vertical sync pulse
|
||||
const bool m_vblank_active; // active level of vertical blanking pulse
|
||||
|
||||
// derived parameters
|
||||
const int m_dots_per_line; // number of dots per scan line
|
||||
const int m_dots_per_row; // number of dots displayed in each scan line
|
||||
const int m_video_scan_lines; // number of active scan lines between VBLANK periods
|
||||
|
||||
// misc. configuration
|
||||
bool m_half_shift; // adjust screen parameters to allow half-dot shifting
|
||||
|
||||
// device callbacks
|
||||
devcb_write_line m_lrc_callback; // line rate clock output (active high)
|
||||
devcb_write_line m_clc_callback; // clear line counter output (active low during blanking)
|
||||
devcb_write8 m_lc_callback; // line counter output
|
||||
devcb_write_line m_lbre_callback; // line buffer recirculate enable output (active high)
|
||||
devcb_write_line m_hsync_callback; // horizontal sync output (polarity may vary by type)
|
||||
devcb_write_line m_vsync_callback; // vertical sync output (polarity may vary by type)
|
||||
devcb_write_line m_vblank_callback; // vertical blanking output (polarity may vary by type)
|
||||
|
||||
// internal registers and control parameters
|
||||
bool m_60hz_refresh; // refresh rate selector (true = f1, false = f0)
|
||||
bool m_cgpi; // character generator program/address mode input
|
||||
u16 m_topr; // top-of-page register
|
||||
u16 m_rsr; // row start register (to be loaded during next row)
|
||||
u16 m_cr; // cursor register
|
||||
u16 m_row_start; // start of current row
|
||||
u16 m_line; // current scan line (starting at HBLANK)
|
||||
|
||||
// output state
|
||||
u8 m_lc; // 4-bit line counter
|
||||
|
||||
// timers
|
||||
emu_timer *m_hblank_start_timer;
|
||||
emu_timer *m_hblank_near_end_timer;
|
||||
emu_timer *m_hsync_on_timer;
|
||||
emu_timer *m_hsync_off_timer;
|
||||
emu_timer *m_vsync_on_timer;
|
||||
emu_timer *m_vsync_off_timer;
|
||||
emu_timer *m_vblank_on_timer;
|
||||
emu_timer *m_vblank_off_timer;
|
||||
};
|
||||
|
||||
// ======================> dp8350_device
|
||||
|
Loading…
Reference in New Issue
Block a user