mirror of
https://github.com/holub/mame
synced 2025-05-21 13:18:56 +03:00
Imported UPD3301 CRTC from MESS. (no whatsnew)
This commit is contained in:
parent
b681899978
commit
1fcf326181
2
.gitattributes
vendored
2
.gitattributes
vendored
@ -1243,6 +1243,8 @@ src/emu/video/tms9927.c svneol=native#text/plain
|
||||
src/emu/video/tms9927.h svneol=native#text/plain
|
||||
src/emu/video/tms9928a.c svneol=native#text/plain
|
||||
src/emu/video/tms9928a.h svneol=native#text/plain
|
||||
src/emu/video/upd3301.c svneol=native#text/plain
|
||||
src/emu/video/upd3301.h svneol=native#text/plain
|
||||
src/emu/video/v9938.c svneol=native#text/plain
|
||||
src/emu/video/v9938.h svneol=native#text/plain
|
||||
src/emu/video/v9938mod.c svneol=native#text/plain
|
||||
|
@ -250,6 +250,7 @@ EMUVIDEOOBJS = \
|
||||
$(EMUVIDEO)/tms34061.o \
|
||||
$(EMUVIDEO)/tms9927.o \
|
||||
$(EMUVIDEO)/tms9928a.o \
|
||||
$(EMUVIDEO)/upd3301.o \
|
||||
$(EMUVIDEO)/v9938.o \
|
||||
$(EMUVIDEO)/vector.o \
|
||||
$(EMUVIDEO)/voodoo.o \
|
||||
|
668
src/emu/video/upd3301.c
Normal file
668
src/emu/video/upd3301.c
Normal file
@ -0,0 +1,668 @@
|
||||
/**********************************************************************
|
||||
|
||||
NEC uPD3301 Programmable CRT Controller emulation
|
||||
|
||||
Copyright MESS Team.
|
||||
Visit http://mamedev.org for licensing and usage restrictions.
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
/*
|
||||
|
||||
TODO:
|
||||
|
||||
- attributes
|
||||
- N interrupt
|
||||
- light pen
|
||||
- reset counters
|
||||
- proper DMA timing (now the whole screen is transferred at the end of the frame,
|
||||
accurate timing requires CCLK timer which kills performance)
|
||||
|
||||
*/
|
||||
|
||||
#include "emu.h"
|
||||
#include "upd3301.h"
|
||||
#include "machine/devhelpr.h"
|
||||
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// MACROS / CONSTANTS
|
||||
//**************************************************************************
|
||||
|
||||
#define LOG 0
|
||||
|
||||
|
||||
#define COMMAND_MASK 0xe0
|
||||
#define COMMAND_RESET 0x00
|
||||
#define COMMAND_START_DISPLAY 0x20
|
||||
#define COMMAND_SET_INTERRUPT_MASK 0x40
|
||||
#define COMMAND_READ_LIGHT_PEN 0x60 // not supported
|
||||
#define COMMAND_LOAD_CURSOR_POSITION 0x80
|
||||
#define COMMAND_RESET_INTERRUPT 0xa0
|
||||
#define COMMAND_RESET_COUNTERS 0xc0 // not supported
|
||||
|
||||
|
||||
#define STATUS_VE 0x10
|
||||
#define STATUS_U 0x08 // not supported
|
||||
#define STATUS_N 0x04 // not supported
|
||||
#define STATUS_E 0x02
|
||||
#define STATUS_LP 0x01 // not supported
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
MODE_NONE,
|
||||
MODE_RESET,
|
||||
MODE_READ_LIGHT_PEN,
|
||||
MODE_LOAD_CURSOR_POSITION,
|
||||
MODE_RESET_COUNTERS
|
||||
};
|
||||
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// GLOBAL VARIABLES
|
||||
//**************************************************************************
|
||||
|
||||
// devices
|
||||
const device_type UPD3301 = upd3301_device_config::static_alloc_device_config;
|
||||
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// DEVICE CONFIGURATION
|
||||
//**************************************************************************
|
||||
|
||||
GENERIC_DEVICE_CONFIG_SETUP(upd3301, "UPD3301")
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_config_complete - perform any
|
||||
// operations now that the configuration is
|
||||
// complete
|
||||
//-------------------------------------------------
|
||||
|
||||
void upd3301_device_config::device_config_complete()
|
||||
{
|
||||
// inherit a copy of the static data
|
||||
const upd3301_interface *intf = reinterpret_cast<const upd3301_interface *>(static_config());
|
||||
if (intf != NULL)
|
||||
*static_cast<upd3301_interface *>(this) = *intf;
|
||||
|
||||
// or initialize to defaults if none provided
|
||||
else
|
||||
{
|
||||
memset(&m_out_int_func, 0, sizeof(m_out_int_func));
|
||||
memset(&m_out_drq_func, 0, sizeof(m_out_drq_func));
|
||||
memset(&m_out_hrtc_func, 0, sizeof(m_out_hrtc_func));
|
||||
memset(&m_out_vrtc_func, 0, sizeof(m_out_vrtc_func));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// INLINE HELPERS
|
||||
//**************************************************************************
|
||||
|
||||
//-------------------------------------------------
|
||||
// set_interrupt -
|
||||
//-------------------------------------------------
|
||||
|
||||
inline void upd3301_device::set_interrupt(int state)
|
||||
{
|
||||
if (LOG) logerror("UPD3301 '%s' Interrupt: %u\n", tag(), state);
|
||||
|
||||
devcb_call_write_line(&m_out_int_func, state);
|
||||
|
||||
if (!state)
|
||||
{
|
||||
m_status &= ~(STATUS_N | STATUS_E);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// set_drq -
|
||||
//-------------------------------------------------
|
||||
|
||||
inline void upd3301_device::set_drq(int state)
|
||||
{
|
||||
if (LOG) logerror("UPD3301 '%s' DRQ: %u\n", tag(), state);
|
||||
|
||||
devcb_call_write_line(&m_out_drq_func, state);
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// set_display -
|
||||
//-------------------------------------------------
|
||||
|
||||
inline void upd3301_device::set_display(int state)
|
||||
{
|
||||
if (state)
|
||||
{
|
||||
m_status |= STATUS_VE;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_status &= ~STATUS_VE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// reset_counters -
|
||||
//-------------------------------------------------
|
||||
|
||||
inline void upd3301_device::reset_counters()
|
||||
{
|
||||
set_interrupt(0);
|
||||
set_drq(0);
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// update_hrtc_timer -
|
||||
//-------------------------------------------------
|
||||
|
||||
inline void upd3301_device::update_hrtc_timer(int state)
|
||||
{
|
||||
int y = m_screen->vpos();
|
||||
|
||||
int next_x = state ? m_h : 0;
|
||||
int next_y = state ? y : ((y + 1) % ((m_l + m_v) * m_config.m_width));
|
||||
|
||||
attotime duration = m_screen->time_until_pos(next_y, next_x);
|
||||
|
||||
m_hrtc_timer->adjust(duration, !state);
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// update_vrtc_timer -
|
||||
//-------------------------------------------------
|
||||
|
||||
inline void upd3301_device::update_vrtc_timer(int state)
|
||||
{
|
||||
int next_y = state ? (m_l * m_r) : 0;
|
||||
|
||||
attotime duration = m_screen->time_until_pos(next_y, 0);
|
||||
|
||||
m_vrtc_timer->adjust(duration, !state);
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// recompute_parameters -
|
||||
//-------------------------------------------------
|
||||
|
||||
inline void upd3301_device::recompute_parameters()
|
||||
{
|
||||
int horiz_pix_total = (m_h + m_z) * m_config.m_width;
|
||||
int vert_pix_total = (m_l + m_v) * m_r;
|
||||
|
||||
attoseconds_t refresh = HZ_TO_ATTOSECONDS(clock()) * horiz_pix_total * vert_pix_total;
|
||||
|
||||
rectangle visarea;
|
||||
|
||||
visarea.min_x = 0;
|
||||
visarea.min_y = 0;
|
||||
visarea.max_x = (m_h * m_config.m_width) - 1;
|
||||
visarea.max_y = (m_l * m_r) - 1;
|
||||
|
||||
if (LOG)
|
||||
{
|
||||
if (LOG) logerror("UPD3301 '%s' Screen: %u x %u @ %f Hz\n", tag(), horiz_pix_total, vert_pix_total, 1 / ATTOSECONDS_TO_DOUBLE(refresh));
|
||||
if (LOG) logerror("UPD3301 '%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);
|
||||
|
||||
update_hrtc_timer(0);
|
||||
update_vrtc_timer(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// LIVE DEVICE
|
||||
//**************************************************************************
|
||||
|
||||
//-------------------------------------------------
|
||||
// upd3301_device - constructor
|
||||
//-------------------------------------------------
|
||||
|
||||
upd3301_device::upd3301_device(running_machine &_machine, const upd3301_device_config &config)
|
||||
: device_t(_machine, config),
|
||||
m_status(0),
|
||||
m_param_count(0),
|
||||
m_data_fifo_pos(0),
|
||||
m_attr_fifo_pos(0),
|
||||
m_input_fifo(0),
|
||||
m_h(80),
|
||||
m_l(20),
|
||||
m_r(10),
|
||||
m_v(6),
|
||||
m_z(32),
|
||||
m_config(config)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_start - device-specific startup
|
||||
//-------------------------------------------------
|
||||
|
||||
void upd3301_device::device_start()
|
||||
{
|
||||
// allocate timers
|
||||
m_hrtc_timer = timer_alloc(TIMER_HRTC);
|
||||
m_vrtc_timer = timer_alloc(TIMER_VRTC);
|
||||
m_drq_timer = timer_alloc(TIMER_DRQ);
|
||||
|
||||
// resolve callbacks
|
||||
devcb_resolve_write_line(&m_out_int_func, &m_config.m_out_int_func, this);
|
||||
devcb_resolve_write_line(&m_out_drq_func, &m_config.m_out_drq_func, this);
|
||||
devcb_resolve_write_line(&m_out_hrtc_func, &m_config.m_out_hrtc_func, this);
|
||||
devcb_resolve_write_line(&m_out_vrtc_func, &m_config.m_out_vrtc_func, this);
|
||||
|
||||
// get the screen device
|
||||
m_screen = m_machine.device<screen_device>(m_config.m_screen_tag);
|
||||
assert(m_screen != NULL);
|
||||
|
||||
// state saving
|
||||
save_item(NAME(m_y));
|
||||
save_item(NAME(m_hrtc));
|
||||
save_item(NAME(m_vrtc));
|
||||
save_item(NAME(m_mode));
|
||||
save_item(NAME(m_status));
|
||||
save_item(NAME(m_param_count));
|
||||
save_item(NAME(m_data_fifo_pos));
|
||||
save_item(NAME(m_attr_fifo_pos));
|
||||
save_item(NAME(m_input_fifo));
|
||||
save_item(NAME(m_mn));
|
||||
save_item(NAME(m_me));
|
||||
save_item(NAME(m_dma_mode));
|
||||
save_item(NAME(m_h));
|
||||
save_item(NAME(m_b));
|
||||
save_item(NAME(m_l));
|
||||
save_item(NAME(m_s));
|
||||
save_item(NAME(m_c));
|
||||
save_item(NAME(m_r));
|
||||
save_item(NAME(m_v));
|
||||
save_item(NAME(m_z));
|
||||
save_item(NAME(m_at1));
|
||||
save_item(NAME(m_at0));
|
||||
save_item(NAME(m_sc));
|
||||
save_item(NAME(m_attr));
|
||||
save_item(NAME(m_attr_blink));
|
||||
save_item(NAME(m_attr_frame));
|
||||
save_item(NAME(m_cm));
|
||||
save_item(NAME(m_cx));
|
||||
save_item(NAME(m_cy));
|
||||
save_item(NAME(m_cursor_blink));
|
||||
save_item(NAME(m_cursor_frame));
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_reset - device-specific reset
|
||||
//-------------------------------------------------
|
||||
|
||||
void upd3301_device::device_reset()
|
||||
{
|
||||
set_interrupt(0);
|
||||
set_drq(0);
|
||||
|
||||
recompute_parameters();
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_clock_changed - handle clock change
|
||||
//-------------------------------------------------
|
||||
|
||||
void upd3301_device::device_clock_changed()
|
||||
{
|
||||
recompute_parameters();
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_timer - handle timer events
|
||||
//-------------------------------------------------
|
||||
|
||||
void upd3301_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case TIMER_HRTC:
|
||||
if (LOG) logerror("UPD3301 '%s' HRTC: %u\n", tag(), param);
|
||||
|
||||
devcb_call_write_line(&m_out_hrtc_func, param);
|
||||
m_hrtc = param;
|
||||
|
||||
update_hrtc_timer(param);
|
||||
break;
|
||||
|
||||
case TIMER_VRTC:
|
||||
if (LOG) logerror("UPD3301 '%s' VRTC: %u\n", tag(), param);
|
||||
|
||||
devcb_call_write_line(&m_out_vrtc_func, param);
|
||||
m_vrtc = param;
|
||||
|
||||
if (param && !m_me)
|
||||
{
|
||||
m_status |= STATUS_E;
|
||||
set_interrupt(1);
|
||||
}
|
||||
|
||||
update_vrtc_timer(param);
|
||||
break;
|
||||
|
||||
case TIMER_DRQ:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// read -
|
||||
//-------------------------------------------------
|
||||
|
||||
READ8_MEMBER( upd3301_device::read )
|
||||
{
|
||||
UINT8 data = 0;
|
||||
|
||||
switch (offset & 0x01)
|
||||
{
|
||||
case 0: // data
|
||||
break;
|
||||
|
||||
case 1: // status
|
||||
data = m_status;
|
||||
m_status &= ~(STATUS_LP | STATUS_E |STATUS_N | STATUS_U);
|
||||
break;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// write -
|
||||
//-------------------------------------------------
|
||||
|
||||
WRITE8_MEMBER( upd3301_device::write )
|
||||
{
|
||||
switch (offset & 0x01)
|
||||
{
|
||||
case 0: // data
|
||||
switch (m_mode)
|
||||
{
|
||||
case MODE_RESET:
|
||||
switch (m_param_count)
|
||||
{
|
||||
case 0:
|
||||
m_dma_mode = BIT(data, 7);
|
||||
m_h = (data & 0x7f) + 2;
|
||||
if (LOG) logerror("UPD3301 '%s' DMA Mode: %s\n", tag(), m_dma_mode ? "character" : "burst");
|
||||
if (LOG) logerror("UPD3301 '%s' H: %u\n", tag(), m_h);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
m_b = ((data >> 6) + 1) * 16;
|
||||
m_l = (data & 0x3f) + 1;
|
||||
if (LOG) logerror("UPD3301 '%s' B: %u\n", tag(), m_b);
|
||||
if (LOG) logerror("UPD3301 '%s' L: %u\n", tag(), m_l);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
m_s = BIT(data, 7);
|
||||
m_c = (data >> 4) & 0x03;
|
||||
m_r = (data & 0x1f) + 1;
|
||||
if (LOG) logerror("UPD3301 '%s' S: %u\n", tag(), m_s);
|
||||
if (LOG) logerror("UPD3301 '%s' C: %u\n", tag(), m_c);
|
||||
if (LOG) logerror("UPD3301 '%s' R: %u\n", tag(), m_r);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
m_v = (data >> 5) + 1;
|
||||
m_z = (data & 0x1f) + 2;
|
||||
if (LOG) logerror("UPD3301 '%s' V: %u\n", tag(), m_v);
|
||||
if (LOG) logerror("UPD3301 '%s' Z: %u\n", tag(), m_z);
|
||||
recompute_parameters();
|
||||
break;
|
||||
|
||||
case 4:
|
||||
m_at1 = BIT(data, 7);
|
||||
m_at0 = BIT(data, 6);
|
||||
m_sc = BIT(data, 5);
|
||||
m_attr = (data & 0x1f) + 1;
|
||||
if (LOG) logerror("UPD3301 '%s' AT1: %u\n", tag(), m_at1);
|
||||
if (LOG) logerror("UPD3301 '%s' AT0: %u\n", tag(), m_at0);
|
||||
if (LOG) logerror("UPD3301 '%s' SC: %u\n", tag(), m_sc);
|
||||
if (LOG) logerror("UPD3301 '%s' ATTR: %u\n", tag(), m_attr);
|
||||
|
||||
m_mode = MODE_NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
m_param_count++;
|
||||
break;
|
||||
|
||||
case MODE_LOAD_CURSOR_POSITION:
|
||||
switch (m_param_count)
|
||||
{
|
||||
case 0:
|
||||
m_cx = data & 0x7f;
|
||||
if (LOG) logerror("UPD3301 '%s' CX: %u\n", tag(), m_cx);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
m_cy = data & 0x3f;
|
||||
if (LOG) logerror("UPD3301 '%s' CY: %u\n", tag(), m_cy);
|
||||
|
||||
m_mode = MODE_NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
m_param_count++;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (LOG) logerror("UPD3301 '%s' Invalid Parameter Byte %02x!\n", tag(), data);
|
||||
}
|
||||
break;
|
||||
|
||||
case 1: // command
|
||||
m_mode = MODE_NONE;
|
||||
m_param_count = 0;
|
||||
|
||||
switch (data & 0xe0)
|
||||
{
|
||||
case COMMAND_RESET:
|
||||
if (LOG) logerror("UPD3301 '%s' Reset\n", tag());
|
||||
m_mode = MODE_RESET;
|
||||
set_display(0);
|
||||
set_interrupt(0);
|
||||
break;
|
||||
|
||||
case COMMAND_START_DISPLAY:
|
||||
if (LOG) logerror("UPD3301 '%s' Start Display\n", tag());
|
||||
set_display(1);
|
||||
reset_counters();
|
||||
break;
|
||||
|
||||
case COMMAND_SET_INTERRUPT_MASK:
|
||||
if (LOG) logerror("UPD3301 '%s' Set Interrupt Mask\n", tag());
|
||||
m_me = BIT(data, 0);
|
||||
m_mn = BIT(data, 1);
|
||||
if (LOG) logerror("UPD3301 '%s' ME: %u\n", tag(), m_me);
|
||||
if (LOG) logerror("UPD3301 '%s' MN: %u\n", tag(), m_mn);
|
||||
break;
|
||||
|
||||
case COMMAND_READ_LIGHT_PEN:
|
||||
if (LOG) logerror("UPD3301 '%s' Read Light Pen\n", tag());
|
||||
m_mode = MODE_READ_LIGHT_PEN;
|
||||
break;
|
||||
|
||||
case COMMAND_LOAD_CURSOR_POSITION:
|
||||
if (LOG) logerror("UPD3301 '%s' Load Cursor Position\n", tag());
|
||||
m_mode = MODE_LOAD_CURSOR_POSITION;
|
||||
m_cm = BIT(data, 0);
|
||||
if (LOG) logerror("UPD3301 '%s' CM: %u\n", tag(), m_cm);
|
||||
break;
|
||||
|
||||
case COMMAND_RESET_INTERRUPT:
|
||||
if (LOG) logerror("UPD3301 '%s' Reset Interrupt\n", tag());
|
||||
set_interrupt(0);
|
||||
break;
|
||||
|
||||
case COMMAND_RESET_COUNTERS:
|
||||
if (LOG) logerror("UPD3301 '%s' Reset Counters\n", tag());
|
||||
m_mode = MODE_RESET_COUNTERS;
|
||||
reset_counters();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// dack_w -
|
||||
//-------------------------------------------------
|
||||
|
||||
WRITE8_MEMBER( upd3301_device::dack_w )
|
||||
{
|
||||
if (m_y >= (m_l * m_r))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_data_fifo_pos < m_h)
|
||||
{
|
||||
m_data_fifo[m_data_fifo_pos][m_input_fifo] = data;
|
||||
m_data_fifo_pos++;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_attr_fifo[m_attr_fifo_pos][m_input_fifo] = data;
|
||||
m_attr_fifo_pos++;
|
||||
}
|
||||
|
||||
if ((m_data_fifo_pos == m_h) && (m_attr_fifo_pos == (m_attr << 1)))
|
||||
{
|
||||
m_input_fifo = !m_input_fifo;
|
||||
|
||||
m_data_fifo_pos = 0;
|
||||
m_attr_fifo_pos = 0;
|
||||
|
||||
draw_scanline();
|
||||
|
||||
if (m_y == (m_l * m_r))
|
||||
{
|
||||
// end DMA transfer
|
||||
set_drq(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// lpen_w -
|
||||
//-------------------------------------------------
|
||||
|
||||
WRITE_LINE_MEMBER( upd3301_device::lpen_w )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// hrtc_r -
|
||||
//-------------------------------------------------
|
||||
|
||||
READ_LINE_MEMBER( upd3301_device::hrtc_r )
|
||||
{
|
||||
return m_hrtc;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// vrtc_r -
|
||||
//-------------------------------------------------
|
||||
|
||||
READ_LINE_MEMBER( upd3301_device::vrtc_r )
|
||||
{
|
||||
return m_vrtc;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// draw_scanline -
|
||||
//-------------------------------------------------
|
||||
|
||||
void upd3301_device::draw_scanline()
|
||||
{
|
||||
for (int lc = 0; lc < m_r; lc++)
|
||||
{
|
||||
for (int sx = 0; sx < m_h; sx++)
|
||||
{
|
||||
int y = m_y + lc;
|
||||
UINT8 cc = m_data_fifo[sx][!m_input_fifo];
|
||||
int hlgt = 0; // TODO
|
||||
int rvv = 0; // TODO
|
||||
int vsp = 0; // TODO
|
||||
int sl0 = 0; // TODO
|
||||
int sl12 = 0; // TODO
|
||||
int csr = m_cm && m_cursor_blink && ((y / m_r) == m_cy) && (sx == m_cx);
|
||||
int gpa = 0; // TODO
|
||||
|
||||
m_config.m_display_func(this, m_bitmap, y, sx, cc, lc, hlgt, rvv, vsp, sl0, sl12, csr, gpa);
|
||||
}
|
||||
}
|
||||
|
||||
m_y += m_r;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// update_screen -
|
||||
//-------------------------------------------------
|
||||
|
||||
void upd3301_device::update_screen(bitmap_t *bitmap, const rectangle *cliprect)
|
||||
{
|
||||
if (m_status & STATUS_VE)
|
||||
{
|
||||
m_y = 0;
|
||||
m_bitmap = bitmap;
|
||||
m_data_fifo_pos = 0;
|
||||
m_attr_fifo_pos = 0;
|
||||
|
||||
m_cursor_frame++;
|
||||
|
||||
if (m_cursor_frame == m_b)
|
||||
{
|
||||
m_cursor_frame = 0;
|
||||
m_cursor_blink = !m_cursor_blink;
|
||||
}
|
||||
|
||||
m_attr_frame++;
|
||||
|
||||
if (m_attr_frame == (m_b << 1))
|
||||
{
|
||||
m_attr_frame = 0;
|
||||
m_attr_blink = !m_attr_blink;
|
||||
}
|
||||
|
||||
// start DMA transfer
|
||||
set_drq(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
bitmap_fill(bitmap, cliprect, get_black_pen(m_machine));
|
||||
}
|
||||
}
|
222
src/emu/video/upd3301.h
Normal file
222
src/emu/video/upd3301.h
Normal file
@ -0,0 +1,222 @@
|
||||
/**********************************************************************
|
||||
|
||||
NEC uPD3301 Programmable CRT Controller emulation
|
||||
|
||||
Copyright MESS Team.
|
||||
Visit http://mamedev.org for licensing and usage restrictions.
|
||||
|
||||
**********************************************************************
|
||||
_____ _____
|
||||
VRTC 1 |* \_/ | 40 Vcc
|
||||
RVV 2 | | 39 SL0
|
||||
CSR 3 | | 38 LC0
|
||||
LPEN 4 | | 37 LC1
|
||||
INT 5 | | 36 LC2
|
||||
DRQ 6 | | 35 LC3
|
||||
_DACK 7 | | 34 VSP
|
||||
A0 8 | | 33 SL12
|
||||
_RD 9 | | 32 GPA
|
||||
_WR 10 | uPD3301 | 31 HLGT
|
||||
_CS 11 | | 30 CC7
|
||||
DB0 12 | | 29 CC6
|
||||
DB1 13 | | 28 CC5
|
||||
DB2 14 | | 27 CC4
|
||||
DB3 15 | | 26 CC3
|
||||
DB4 16 | | 25 CC2
|
||||
DB5 17 | | 24 CC1
|
||||
DB6 18 | | 23 CC0
|
||||
DB7 19 | | 22 CCLK
|
||||
GND 20 |_____________| 21 HRTC
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef __UPD3301__
|
||||
#define __UPD3301__
|
||||
|
||||
#include "emu.h"
|
||||
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// MACROS / CONSTANTS
|
||||
//**************************************************************************
|
||||
|
||||
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// INTERFACE CONFIGURATION MACROS
|
||||
//**************************************************************************
|
||||
|
||||
#define MCFG_UPD3301_ADD(_tag, _clock, _intrf) \
|
||||
MCFG_DEVICE_ADD(_tag, UPD3301, _clock) \
|
||||
MCFG_DEVICE_CONFIG(_intrf)
|
||||
|
||||
|
||||
#define UPD3301_INTERFACE(name) \
|
||||
const upd3301_interface (name) =
|
||||
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// TYPE DEFINITIONS
|
||||
//**************************************************************************
|
||||
|
||||
// ======================> upd3301_display_pixels_func
|
||||
|
||||
typedef void (*upd3301_display_pixels_func)(device_t *device, bitmap_t *bitmap, int y, int sx, UINT8 cc, UINT8 lc, int hlgt, int rvv, int vsp, int sl0, int sl12, int csr, int gpa);
|
||||
#define UPD3301_DISPLAY_PIXELS(name) void name(device_t *device, bitmap_t *bitmap, int y, int sx, UINT8 cc, UINT8 lc, int hlgt, int rvv, int vsp, int sl0, int sl12, int csr, int gpa)
|
||||
|
||||
|
||||
// ======================> upd3301_interface
|
||||
|
||||
struct upd3301_interface
|
||||
{
|
||||
const char *m_screen_tag; // screen we are acting on
|
||||
int m_width; // char width in pixels
|
||||
|
||||
upd3301_display_pixels_func m_display_func;
|
||||
|
||||
devcb_write_line m_out_int_func;
|
||||
devcb_write_line m_out_drq_func;
|
||||
devcb_write_line m_out_hrtc_func;
|
||||
devcb_write_line m_out_vrtc_func;
|
||||
};
|
||||
|
||||
|
||||
|
||||
// ======================> upd3301_device_config
|
||||
|
||||
class upd3301_device_config : public device_config,
|
||||
public upd3301_interface
|
||||
{
|
||||
friend class upd3301_device;
|
||||
|
||||
// construction/destruction
|
||||
upd3301_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock);
|
||||
|
||||
public:
|
||||
// allocators
|
||||
static device_config *static_alloc_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock);
|
||||
virtual device_t *alloc_device(running_machine &machine) const;
|
||||
|
||||
protected:
|
||||
// device_config overrides
|
||||
virtual void device_config_complete();
|
||||
};
|
||||
|
||||
|
||||
|
||||
// ======================> upd3301_device
|
||||
|
||||
class upd3301_device : public device_t
|
||||
{
|
||||
friend class upd3301_device_config;
|
||||
|
||||
// construction/destruction
|
||||
upd3301_device(running_machine &_machine, const upd3301_device_config &_config);
|
||||
|
||||
public:
|
||||
DECLARE_READ8_MEMBER( read );
|
||||
DECLARE_WRITE8_MEMBER( write );
|
||||
DECLARE_WRITE8_MEMBER( dack_w );
|
||||
DECLARE_WRITE_LINE_MEMBER( lpen_w );
|
||||
DECLARE_READ_LINE_MEMBER( hrtc_r );
|
||||
DECLARE_READ_LINE_MEMBER( vrtc_r );
|
||||
|
||||
void update_screen(bitmap_t *bitmap, const rectangle *cliprect);
|
||||
|
||||
protected:
|
||||
// device-level overrides
|
||||
virtual void device_start();
|
||||
virtual void device_reset();
|
||||
virtual void device_clock_changed();
|
||||
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
|
||||
|
||||
private:
|
||||
static const device_timer_id TIMER_HRTC = 0;
|
||||
static const device_timer_id TIMER_VRTC = 1;
|
||||
static const device_timer_id TIMER_DRQ = 2;
|
||||
|
||||
inline void set_interrupt(int state);
|
||||
inline void set_drq(int state);
|
||||
inline void set_display(int state);
|
||||
inline void reset_counters();
|
||||
inline void update_hrtc_timer(int state);
|
||||
inline void update_vrtc_timer(int state);
|
||||
inline void recompute_parameters();
|
||||
|
||||
void draw_scanline();
|
||||
|
||||
devcb_resolved_write_line m_out_int_func;
|
||||
devcb_resolved_write_line m_out_drq_func;
|
||||
devcb_resolved_write_line m_out_hrtc_func;
|
||||
devcb_resolved_write_line m_out_vrtc_func;
|
||||
|
||||
screen_device *m_screen;
|
||||
|
||||
// screen drawing
|
||||
bitmap_t *m_bitmap; // bitmap
|
||||
int m_y; // current scanline
|
||||
int m_hrtc; // horizontal retrace
|
||||
int m_vrtc; // vertical retrace
|
||||
|
||||
// live state
|
||||
int m_mode; // command mode
|
||||
UINT8 m_status; // status register
|
||||
int m_param_count; // parameter count
|
||||
|
||||
// FIFOs
|
||||
UINT8 m_data_fifo[80][2]; // row data FIFO
|
||||
UINT8 m_attr_fifo[40][2]; // attribute FIFO
|
||||
int m_data_fifo_pos; // row data FIFO position
|
||||
int m_attr_fifo_pos; // attribute FIFO position
|
||||
int m_input_fifo; // which FIFO is in input mode
|
||||
|
||||
// interrupts
|
||||
int m_mn; // disable special character interrupt
|
||||
int m_me; // disable end of screen interrupt
|
||||
int m_dma_mode; // DMA mode
|
||||
|
||||
// screen geometry
|
||||
int m_h; // characters per line
|
||||
int m_b; // cursor blink time
|
||||
int m_l; // lines per screen
|
||||
int m_s; // display every other line
|
||||
int m_c; // cursor mode
|
||||
int m_r; // lines per character
|
||||
int m_v; // vertical blanking height
|
||||
int m_z; // horizontal blanking width
|
||||
|
||||
// attributes
|
||||
int m_at1; //
|
||||
int m_at0; //
|
||||
int m_sc; //
|
||||
int m_attr; // attributes per row
|
||||
int m_attr_blink; // attribute blink
|
||||
int m_attr_frame; // attribute blink frame counter
|
||||
|
||||
// cursor
|
||||
int m_cm; // cursor visible
|
||||
int m_cx; // cursor column
|
||||
int m_cy; // cursor row
|
||||
int m_cursor_blink; // cursor blink
|
||||
int m_cursor_frame; // cursor blink frame counter
|
||||
|
||||
// timers
|
||||
emu_timer *m_hrtc_timer;
|
||||
emu_timer *m_vrtc_timer;
|
||||
emu_timer *m_drq_timer;
|
||||
|
||||
const upd3301_device_config &m_config;
|
||||
};
|
||||
|
||||
|
||||
// device type definition
|
||||
extern const device_type UPD3301;
|
||||
|
||||
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user