Preliminary emulation of National DP8350 CRT controller family

This commit is contained in:
AJR 2018-09-25 00:51:14 -04:00
parent 3d3eda2b32
commit fad9283ecc
7 changed files with 453 additions and 10 deletions

View File

@ -149,6 +149,18 @@ if (VIDEOS["DM9368"]~=null) then
}
end
--------------------------------------------------
--
--@src/devices/video/dp8350.h,VIDEOS["DP8350"] = true
--------------------------------------------------
if (VIDEOS["DP8350"]~=null) then
files {
MAME_DIR .. "src/devices/video/dp8350.cpp",
MAME_DIR .. "src/devices/video/dp8350.h",
}
end
--------------------------------------------------
--
--@src/devices/video/ef9340_1.h,VIDEOS["EF9340_1"] = true

View File

@ -288,6 +288,7 @@ VIDEOS["CESBLIT"] = true
VIDEOS["CRTC_EGA"] = true
--VIDEOS["DL1416"] = true
VIDEOS["DM9368"] = true
VIDEOS["DP8350"] = true
--VIDEOS["EF9340_1"] = true
--VIDEOS["EF9345"] = true
--VIDEOS["EF9364"] = true

View File

@ -297,6 +297,7 @@ VIDEOS["CRT9212"] = true
VIDEOS["CRTC_EGA"] = true
VIDEOS["DL1416"] = true
VIDEOS["DM9368"] = true
VIDEOS["DP8350"] = true
VIDEOS["EF9340_1"] = true
VIDEOS["EF9345"] = true
VIDEOS["EF9364"] = true

View File

@ -0,0 +1,289 @@
// license:BSD-3-Clause
// copyright-holders:AJR
/**********************************************************************
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.
National released the DP8350 and a few other standard versions.
DP8367 appears to have originally been a custom mask variant
ordered by Hewlett-Packard, though it is listed as option I in
later datasheets; its parameters have been derived from the
information presented in Manual Part No. 13220-91087.
Variant Dot rate Monitor type
------- -------- ------------
DP8350 10.92 MHz Ball Brothers TV-12, TV-120, etc.
DP8352 7.02 MHz RS-170 compatible
DP8353 17.6256 MHz Motorola M3003
DP8367 25.7715 MHz HP 13220
**********************************************************************/
#include "emu.h"
#include "video/dp8350.h"
#include "screen.h"
//**************************************************************************
// GLOBAL VARIABLES
//**************************************************************************
// device type definitions
DEFINE_DEVICE_TYPE(DP8350, dp8350_device, "dp8350", "DP8350 CRTC")
DEFINE_DEVICE_TYPE(DP8367, dp8367_device, "dp8367", "DP8367 CRTC")
//**************************************************************************
// DEVICE IMPLEMENTATION
//**************************************************************************
//-------------------------------------------------
// dp835x_device - constructor
//-------------------------------------------------
dp835x_device::dp835x_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock,
int char_width, int char_height, int chars_per_row, int rows_per_frame,
int vsync_delay_f1, int vsync_width_f1, int vblank_interval_f1,
int vsync_delay_f0, int vsync_width_f0, int vblank_interval_f0,
int chars_per_line, int hsync_delay, int hsync_width, int vblank_stop,
bool cursor_on_all_lines, int lbc_0_width, int hsync_serration,
bool hsync_active, bool vsync_active, bool vblank_active)
: device_t(mconfig, type, tag, owner, clock)
, device_video_interface(mconfig, *this)
, m_char_width(char_width)
, m_char_height(char_height)
, m_chars_per_row(chars_per_row)
, m_rows_per_frame(rows_per_frame)
, m_vsync_delay{vsync_delay_f0, vsync_delay_f1}
, m_vsync_width{vsync_width_f0, vsync_width_f1}
, m_vblank_interval{vblank_interval_f0, vblank_interval_f1}
, m_chars_per_line(chars_per_line)
, m_hsync_delay(hsync_delay)
, m_hsync_width(hsync_width)
, m_vblank_stop(vblank_stop)
, m_cursor_on_all_lines(cursor_on_all_lines)
, m_lbc_0_width(lbc_0_width)
, m_hsync_serration(hsync_serration)
, m_hsync_active(hsync_active)
, m_vsync_active(vsync_active)
, m_vblank_active(vblank_active)
, m_vblank_callback(*this)
, m_60hz_refresh(true)
{
// many parameters are not used yet
(void)m_vsync_delay;
(void)m_vsync_width;
(void)m_hsync_delay;
(void)m_hsync_width;
(void)m_vblank_stop;
(void)m_cursor_on_all_lines;
(void)m_lbc_0_width;
(void)m_hsync_serration;
(void)m_hsync_active;
(void)m_vsync_active;
}
//-------------------------------------------------
// dp8350_device - constructor
//-------------------------------------------------
dp8350_device::dp8350_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: dp835x_device(mconfig, DP8350, tag, owner, clock,
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
true, 4, 0,
true, false, true)
{
}
//-------------------------------------------------
// dp8367_device - constructor
//-------------------------------------------------
dp8367_device::dp8367_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: dp835x_device(mconfig, DP8367, tag, owner, clock,
9, 15, 80, 26,
0, 19, 25,
38, 64, 108,
115, -16, 7, 1, // value of vblank_stop assumed
true, 5, 0, // values assumed
true, true, true)
{
}
//-------------------------------------------------
// device_config_complete - finalise device
// configuration
//-------------------------------------------------
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];
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);
else
screen().set_raw(clock(), dots_per_line, 0, dots_per_row, lines_per_frame, 0, m_char_height * m_rows_per_frame);
}
}
//-------------------------------------------------
// device_resolve_objects - resolve objects that
// may be needed for other devices to set
// initial conditions at start time
//-------------------------------------------------
void dp835x_device::device_resolve_objects()
{
//m_hsync_callback.resolve_safe();
//m_vsync_callback.resolve_safe();
m_vblank_callback.resolve_safe();
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void dp835x_device::device_start()
{
screen().register_vblank_callback(vblank_state_delegate(&dp835x_device::screen_vblank, this));
save_item(NAME(m_60hz_refresh));
}
//-------------------------------------------------
// device_reset - device-specific reset
//-------------------------------------------------
void dp835x_device::device_reset()
{
}
//-------------------------------------------------
// device_clock_changed - called when the
// device clock is altered in any way
//-------------------------------------------------
void dp835x_device::device_clock_changed()
{
reconfigure_screen();
}
//-------------------------------------------------
// reconfigure_screen - update screen parameters
//-------------------------------------------------
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];
attoseconds_t refresh = clocks_to_attotime(lines_per_frame * dots_per_line).as_attoseconds();
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);
}
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);
}
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),
m_60hz_refresh ? 1 : 0,
clock() / (dots_per_line * 1000.0),
clock() / (m_char_width * 1000000.0),
clock() / 1000000.0);
}
//-------------------------------------------------
// refresh_control - set or configure one of two
// field refresh rates (f1 = 60 Hz, f0 = 50 Hz)
//-------------------------------------------------
WRITE_LINE_MEMBER(dp835x_device::refresh_control)
{
if (m_60hz_refresh != bool(state))
{
m_60hz_refresh = state;
if (started())
reconfigure_screen();
}
}
//-------------------------------------------------
// register_load - write to one of three CRTC
// address registers
//-------------------------------------------------
void dp835x_device::register_load(u8 rs, u16 addr)
{
addr &= 0xfff;
switch (rs & 3)
{
case 0:
default:
// No Select
break;
case 1:
// Top-of-Page
logerror("Top-of-Page Register = %03X\n", addr);
break;
case 2:
// Row Start
logerror("Row Start Register = %03X\n", addr);
break;
case 3:
// Cursor
logerror("Cursor Register = %03X\n", addr);
break;
}
}
//-------------------------------------------------
// vblank_r - report vertical blanking state
//-------------------------------------------------
READ_LINE_MEMBER(dp835x_device::vblank_r)
{
return bool(screen().vblank()) == m_vblank_active;
}
//-------------------------------------------------
// screen_vblank - vertical blanking handler
//-------------------------------------------------
void dp835x_device::screen_vblank(screen_device &screen, bool state)
{
m_vblank_callback(state == m_vblank_active);
}

132
src/devices/video/dp8350.h Normal file
View File

@ -0,0 +1,132 @@
// license:BSD-3-Clause
// copyright-holders:AJR
/**********************************************************************
National Semiconductor DP8350 Series CRT Controllers
***********************************************************************
_____ _____
RSB 1 |* \__/ | 40 Vcc
VBLANK 2 | | 39 RSA
50/60 HZ 3 | | 38 RL
VSYNC 4 | | 37 RAE
FULL/HALF 5 | | 36 A0
LC3 6 | | 35 A1
LC2 7 | | 34 A2
LC1 8 | | 33 A3
LC0 9 | | 32 A4
CLC 10 | | 31 A5
CGP 11 | DP835X | 30 A6
LBRE 12 | | 29 A7
LRC 13 | | 28 A8
HSYNC 14 | | 27 A9
RESET 15 | | 26 A10
LBC 16 | | 25 A11
ECLC 17 | | 24 LCGA
LVSR 18 | | 23 DRC
CUR 19 | | 22 X2
GND 20 |______________| 21 X1
**********************************************************************/
#ifndef MAME_VIDEO_DP8350_H
#define MAME_VIDEO_DP8350_H
#pragma once
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
// ======================> dp835x_device
class dp835x_device : public device_t, public device_video_interface
{
public:
// device configuration
auto vblank_callback() { return m_vblank_callback.bind(); }
void set_half_shift(bool half_shift) { m_half_shift = half_shift; }
// write handlers
DECLARE_WRITE_LINE_MEMBER(refresh_control);
void register_load(u8 rs, u16 addr);
// read handlers
DECLARE_READ_LINE_MEMBER(vblank_r);
protected:
// base type constructor
dp835x_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock,
int char_width, int char_height, int chars_per_row, int rows_per_frame,
int vsync_delay_f1, int vsync_width_f1, int vblank_interval_f1,
int vsync_delay_f0, int vsync_width_f0, int vblank_interval_f0,
int chars_per_line, int hsync_delay, int hsync_width, int vblank_stop,
bool cursor_on_all_lines, int lbc_0_width, int hsync_serration,
bool hsync_active, bool vsync_active, bool vblank_active);
// device-specific overrides
virtual void device_config_complete() override;
virtual void device_resolve_objects() override;
virtual void device_start() override;
virtual void device_clock_changed() override;
virtual void device_reset() override;
private:
// internal helpers
void reconfigure_screen();
void screen_vblank(screen_device &screen, bool state);
// mask parameters
const int m_char_width; // character field cell size (width in dots)
const int m_char_height; // character field cell size (height in scan lines)
const int m_chars_per_row; // video characters per row
const int m_rows_per_frame; // video characters per frame
const int m_vsync_delay[2]; // delay from VBLANK start to VSYNC in scan lines
const int m_vsync_width[2]; // vertical sync width in scan lines
const int m_vblank_interval[2]; // scan lines of vertical blanking
const int m_chars_per_line; // character times per scan line
const int m_hsync_delay; // delay from HBLANK start to HSYNC in character times
const int m_hsync_width; // horizontal sync width in character times
const int m_vblank_stop; // VBLANK stop before video start in scan lines
const bool m_cursor_on_all_lines; // true if cursor active on all scan lines of row
const int m_lbc_0_width; // width of LBC 0 output within character time
const int m_hsync_serration; // width of HSYNC pulse serrations within VSYNC (0 if unused)
const bool m_hsync_active; // active level of horizontal sync pulse
const bool m_vsync_active; // active level of vertical sync pulse
const bool m_vblank_active; // active level of vertical blanking pulse
// misc. configuration
bool m_half_shift; // adjust screen parameters to allow half-dot shifting
// device callbacks
//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)
};
// ======================> dp8350_device
class dp8350_device : public dp835x_device
{
public:
// device constructor
dp8350_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
};
// ======================> dp8367_device
class dp8367_device : public dp835x_device
{
public:
// device constructor
dp8367_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
};
// device type declarations
DECLARE_DEVICE_TYPE(DP8350, dp8350_device)
DECLARE_DEVICE_TYPE(DP8367, dp8367_device)
#endif // MAME_VIDEO_DP8350_H

View File

@ -12,7 +12,7 @@
#include "machine/bankdev.h"
#include "machine/i8243.h"
#include "machine/ins8250.h"
//#include "video/dp8350.h"
#include "video/dp8350.h"
#include "screen.h"
class hazl1420_state : public driver_device
@ -23,7 +23,7 @@ public:
, m_maincpu(*this, "maincpu")
, m_bankdev(*this, "bankdev")
, m_ioexp(*this, "ioexp%u", 0U)
, m_screen(*this, "screen")
, m_crtc(*this, "crtc")
{
}
@ -46,7 +46,7 @@ private:
required_device<mcs48_cpu_device> m_maincpu;
required_device<address_map_bank_device> m_bankdev;
required_device_array<i8243_device, 2> m_ioexp;
required_device<screen_device> m_screen;
required_device<dp8350_device> m_crtc;
};
void hazl1420_state::p1_w(u8 data)
@ -57,7 +57,7 @@ void hazl1420_state::p1_w(u8 data)
u8 hazl1420_state::p2_r()
{
u8 result = m_screen->vblank() ? 0xf0 : 0xe0;
u8 result = 0xe0 | (m_crtc->vblank_r() << 4);
result |= m_ioexp[0]->p2_r() & m_ioexp[1]->p2_r();
return result;
}
@ -187,12 +187,11 @@ void hazl1420_state::hazl1420(machine_config &config)
INS8250(config, "ace", 2'764'800);
//DP8350(config, "crtc", 10.92_MHz_XTAL);
DP8350(config, m_crtc, 10.92_MHz_XTAL).set_screen("screen");
m_crtc->vblank_callback().set_inputline(m_maincpu, MCS48_INPUT_IRQ);
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
screen.set_raw(10.92_MHz_XTAL, 700, 0, 560, 260, 0, 240);
screen.set_screen_update(FUNC(hazl1420_state::screen_update));
screen.screen_vblank().set_inputline(m_maincpu, MCS48_INPUT_IRQ);
}
ROM_START(hazl1420)

View File

@ -10,7 +10,7 @@ Skeleton driver for HP-2620 series display terminals.
#include "cpu/z80/z80.h"
#include "machine/mos6551.h"
#include "machine/nvram.h"
//#include "video/dp8350.h"
#include "video/dp8350.h"
#include "screen.h"
class hp2620_state : public driver_device
@ -19,6 +19,7 @@ public:
hp2620_state(const machine_config &mconfig, device_type type, const char *tag)
: driver_device(mconfig, type, tag)
, m_maincpu(*this, "maincpu")
, m_crtc(*this, "crtc")
, m_p_chargen(*this, "chargen")
, m_nvram(*this, "nvram")
{ }
@ -32,6 +33,7 @@ private:
DECLARE_WRITE8_MEMBER(keydisp_w);
DECLARE_READ8_MEMBER(sysstat_r);
DECLARE_WRITE8_MEMBER(modem_w);
void crtc_w(offs_t offset, u8 data);
u32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
@ -39,6 +41,7 @@ private:
void mem_map(address_map &map);
required_device<cpu_device> m_maincpu;
required_device<dp8367_device> m_crtc;
required_region_ptr<u8> m_p_chargen;
required_shared_ptr<u8> m_nvram;
};
@ -77,9 +80,15 @@ WRITE8_MEMBER(hp2620_state::modem_w)
{
}
void hp2620_state::crtc_w(offs_t offset, u8 data)
{
m_crtc->register_load(data & 3, offset & 0xfff);
}
void hp2620_state::mem_map(address_map &map)
{
map(0x0000, 0xbfff).rom().region("maincpu", 0);
map(0x8000, 0xbfff).w(FUNC(hp2620_state::crtc_w));
map(0xc000, 0xffff).ram();
}
@ -107,10 +116,10 @@ void hp2620_state::hp2622(machine_config &config)
NVRAM(config, "nvram", nvram_device::DEFAULT_ALL_0); // 5101 (A7 tied to GND) + battery (+ wait states)
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
screen.set_raw(25.7715_MHz_XTAL, 1035, 0, 720, 415, 0, 390); // 498 total lines in 50 Hz mode
screen.set_screen_update(FUNC(hp2620_state::screen_update));
//DP8367(config, "crtc", 25.7715_MHz_XTAL).set_screen("screen");
DP8367(config, m_crtc, 25.7715_MHz_XTAL).set_screen("screen");
m_crtc->set_half_shift(true);
mos6551_device &acia(MOS6551(config, "acia", 0)); // SY6551
acia.set_xtal(25.7715_MHz_XTAL / 14); // 1.84 MHz