summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/video/upd7220.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/video/upd7220.cpp')
-rw-r--r--src/devices/video/upd7220.cpp1298
1 files changed, 777 insertions, 521 deletions
diff --git a/src/devices/video/upd7220.cpp b/src/devices/video/upd7220.cpp
index d8697222485..95fe02f0326 100644
--- a/src/devices/video/upd7220.cpp
+++ b/src/devices/video/upd7220.cpp
@@ -1,64 +1,74 @@
// license:BSD-3-Clause
-// copyright-holders:Angelo Salese, Miodrag Milanovic, Carl
-/**********************************************************************
+// copyright-holders:Angelo Salese, Miodrag Milanovic, Carl, Brian Johnson
+/**************************************************************************************************
+
+Intel 82720 Graphics Display Controller emulation
+a.k.a. NEC uPD7220
+
+TODO:
+- implement FIFO as ring buffer;
+- incomplete / unimplemented FIGD / GCHRD draw modes;
+\- FIGD character
+\- slanted character
+- read-modify-write cycle (fixed by now?);
+- a5105: has a FIFO bug with the RDAT, should be a lot larger when it scrolls up.
+ Can be fixed with a DRDY mechanism for RDAT/WDAT (fixed by now?);
+- later pc9801/pc9821 machines: throws "Invalid command byte 05" (zettmj on Epson logo),
+ actual undocumented command to reset something?
+- wide mode (32-bit access);
+- microbx2: sets mode=0x1f (interlace), oddly cuts off area scroll on prompt (double height chars?)
+ while DEMO.1 don't.
+- repeat fields interlace mode;
+- support non-draw on retrace mode (pc98 bitmap layer -> potential raster effects), better
+ honoring of visible area (bail out thru m_al, cutting off unnecessary comparisons);
+- light pen;
+
+**************************************************************************************************/
- Intel 82720 Graphics Display Controller emulation
-
-**********************************************************************/
-
-/*
-
- TODO:
-
- - implement FIFO as ring buffer
- - commands
- - DMAR
- - DMAW
- - incomplete / unimplemented FIGD / GCHRD draw modes
- - FIGD character
- - slanted character
- - read-modify-write cycle
- - read data
- - modify data
- - write data
- - QX-10 diagnostic test has positioning bugs with the bitmap display test;
- - QX-10 diagnostic test misses the zooming factor (external pin);
- - compis2 SAD address for bitmap is 0x20000 for whatever reason (presumably missing banking);
- - A5105 has a FIFO bug with the RDAT, should be a lot larger when it scrolls up.
- The problem is that DMA-ing with RDAT/WDAT shouldn't be instant;
-
- - honor visible area
- - wide mode (32-bit access)
- - light pen
- - dad and mask are the same, in figd dad is shifted every step and when msb or lsb are 1 ead is advanced in x dir
-
-*/
#include "emu.h"
#include "upd7220.h"
#include "screen.h"
-//#define VERBOSE 1
-#include "logmacro.h"
+#define LOG_CRTC (1U << 1)
+#define LOG_DRAW (1U << 2)
+#define LOG_AREA (1U << 3) // printout works best with -oslog
+#define LOG_CMD (1U << 4)
+#define LOG_CMD2 (1U << 5) // DE related commands
+#define LOG_CMD3 (1U << 6) // memory interface (RDAT/WDAT)
+#define LOG_CMD4 (1U << 7) // DMA
+#define VERBOSE (LOG_GENERAL)
+//#define LOG_OUTPUT_FUNC osd_printf_info
+#include "logmacro.h"
+#define LOGCRTC(...) LOGMASKED(LOG_CRTC, __VA_ARGS__)
+#define LOGDRAW(...) LOGMASKED(LOG_DRAW, __VA_ARGS__)
+#define LOGAREA(...) LOGMASKED(LOG_AREA, __VA_ARGS__)
+#define LOGCMD(...) LOGMASKED(LOG_CMD, __VA_ARGS__)
+#define LOGCMD2(...) LOGMASKED(LOG_CMD2, __VA_ARGS__)
+#define LOGCMD3(...) LOGMASKED(LOG_CMD3, __VA_ARGS__)
+#define LOGCMD4(...) LOGMASKED(LOG_CMD4, __VA_ARGS__)
//**************************************************************************
// MACROS / CONSTANTS
//**************************************************************************
-// todo typedef
+// TODO: typedef
enum
{
COMMAND_INVALID = -1,
COMMAND_RESET,
+ COMMAND_RESET2,
+ COMMAND_RESET3,
COMMAND_SYNC,
COMMAND_VSYNC,
COMMAND_CCHAR,
COMMAND_START,
- COMMAND_BCTRL,
+ COMMAND_BLANK,
+ COMMAND_BLANK2,
COMMAND_ZOOM,
COMMAND_CURS,
COMMAND_PRAM,
@@ -73,8 +83,7 @@ enum
COMMAND_LPRD,
COMMAND_DMAR,
COMMAND_DMAW,
- COMMAND_5A,
- COMMAND_05
+ COMMAND_5A
};
enum
@@ -91,12 +100,14 @@ enum
};
#define UPD7220_COMMAND_RESET 0x00
+#define UPD7220_COMMAND_RESET2 0x01
+#define UPD7220_COMMAND_RESET3 0x09
#define UPD7220_COMMAND_SYNC 0x0e // & 0xfe
#define UPD7220_COMMAND_VSYNC 0x6e // & 0xfe
#define UPD7220_COMMAND_CCHAR 0x4b
#define UPD7220_COMMAND_START 0x6b
-#define UPD7220_COMMAND_BCTRL 0x0c // & 0xfe
-#define UPD7220_COMMAND_05 0x05
+#define UPD7220_COMMAND_BLANK 0x0c // & 0xfe
+#define UPD7220_COMMAND_BLANK2 0x05
#define UPD7220_COMMAND_ZOOM 0x46
#define UPD7220_COMMAND_CURS 0x49
#define UPD7220_COMMAND_PRAM 0x70 // & 0xf0
@@ -146,6 +157,7 @@ static constexpr int y_dir[8] = { 1, 1, 0,-1,-1,-1, 0, 1};
// devices
DEFINE_DEVICE_TYPE(UPD7220, upd7220_device, "upd7220", "NEC uPD7220")
+DEFINE_DEVICE_TYPE(UPD7220A, upd7220a_device, "upd7220a", "NEC uPD7220A")
// default address map
@@ -163,6 +175,11 @@ ROM_START( upd7220 )
ROM_LOAD( "upd7220.bin", 0x000, 0x100, CRC(3c92b218) SHA1(e154b3106a80c9c98d9f2ee18efcd7f4b4aa7d49) )
ROM_END
+ROM_START( upd7220a )
+ ROM_REGION( 0x100, "upd7220", 0 )
+ ROM_LOAD( "upd7220a.bin", 0x000, 0x100, NO_DUMP )
+ROM_END
+
//-------------------------------------------------
// memory_space_config - return a description of
@@ -186,31 +203,16 @@ const tiny_rom_entry *upd7220_device::device_rom_region() const
return ROM_NAME( upd7220 );
}
+const tiny_rom_entry *upd7220a_device::device_rom_region() const
+{
+ return ROM_NAME( upd7220a );
+}
//**************************************************************************
// INLINE HELPERS
//**************************************************************************
-//-------------------------------------------------
-// readbyte - read a byte at the given address
-//-------------------------------------------------
-
-inline uint8_t upd7220_device::readbyte(offs_t address)
-{
- return space().read_byte(address);
-}
-
-
-//-------------------------------------------------
-// writebyte - write a byte at the given address
-//-------------------------------------------------
-
-inline void upd7220_device::writebyte(offs_t address, uint8_t data)
-{
- space().write_byte(address, data);
-}
-
inline uint16_t upd7220_device::readword(offs_t address)
{
return space().read_word(address);
@@ -329,6 +331,12 @@ inline void upd7220_device::dequeue(uint8_t *data, int *flag)
if (m_fifo_ptr == -1)
m_sr &= ~UPD7220_SR_DATA_READY;
}
+ else
+ {
+ // TODO: underflow details
+ // pc9821:skinpan does SR checks over the wrong port during intro ...
+ *data = 0xff;
+ }
}
@@ -338,7 +346,12 @@ inline void upd7220_device::dequeue(uint8_t *data, int *flag)
inline void upd7220_device::update_vsync_timer(int state)
{
- int next_y = state ? m_vs : 0;
+ const int vert_mult = (m_mode & UPD7220_MODE_INTERLACE_MASK) == UPD7220_MODE_INTERLACE_ON ? 2 : 1;
+
+ // page 6-68, route vsync so that top is start of back porch, end is at sync time
+ // (at bottom of MAME vpos() mechanism)
+ // - pc9801:lemmings and pc9801:spindiz2 cares
+ int next_y = state ? 0 : (m_vbp + m_al + m_vfp) * vert_mult;
attotime duration = screen().time_until_pos(next_y, 0);
@@ -352,10 +365,11 @@ inline void upd7220_device::update_vsync_timer(int state)
inline void upd7220_device::update_hsync_timer(int state)
{
+ const int horiz_mult = (m_mode & UPD7220_MODE_DISPLAY_MASK) == UPD7220_MODE_DISPLAY_GRAPHICS ? 16 : 8;
int y = screen().vpos();
- int next_x = state ? m_hs : 0;
- int next_y = state ? y : ((y + 1) % m_al);
+ int next_x = state ? m_hs * horiz_mult : 0;
+ int next_y = state ? y : ((y + 1) % (m_vs + m_vbp + m_al + m_vfp - 1));
attotime duration = screen().time_until_pos(next_y, next_x);
@@ -384,19 +398,18 @@ inline void upd7220_device::update_blank_timer(int state)
// recompute_parameters -
//-------------------------------------------------
+void upd7220_device::device_clock_changed()
+{
+ recompute_parameters();
+}
+
inline void upd7220_device::recompute_parameters()
{
- int horiz_mult = 16, vert_mult = 1;
- /* TODO: assume that the pitch also controls number of horizontal pixels in a single cell */
- // horiz_mult = 4 if both mixed and interlace?
- if((m_mode & UPD7220_MODE_DISPLAY_MASK) == UPD7220_MODE_DISPLAY_MIXED)
- horiz_mult = 8;
- else if((m_mode & UPD7220_MODE_INTERLACE_MASK) == UPD7220_MODE_INTERLACE_ON)
- {
- // in interlaced mode every line contains both fields
- horiz_mult = 8; // TODO this breaks compis uhrg video, characters are 16 pixels wide in interlaced mode too
- vert_mult = 2;
- }
+ // microbx2 wants horizontal multiplier of x16
+ // pc9801:diremono sets up m_mode to be specifically in character mode, wanting x8 here
+ // TODO: verify compis uhrg video & high reso Hyper 98
+ const int horiz_mult = (m_mode & UPD7220_MODE_DISPLAY_MASK) == UPD7220_MODE_DISPLAY_GRAPHICS ? 16 : 8;
+ const int vert_mult = (m_mode & UPD7220_MODE_INTERLACE_MASK) == UPD7220_MODE_INTERLACE_ON ? 2 : 1;
int horiz_pix_total = (m_hs + m_hbp + m_hfp + m_aw) * horiz_mult;
int vert_pix_total = (m_vs + m_vbp + m_al + m_vfp) * vert_mult;
@@ -415,14 +428,15 @@ inline void upd7220_device::recompute_parameters()
m_vbp, //m_vs + m_vbp;
m_al * vert_mult + m_vbp - 1);//vert_pix_total - m_vfp - 1;
- LOG("uPD7220 Screen: %u x %u @ %f Hz\n", horiz_pix_total, vert_pix_total, 1 / ATTOSECONDS_TO_DOUBLE(refresh));
- LOG("Visible Area: (%u, %u) - (%u, %u)\n", visarea.left(), visarea.top(), visarea.right(), visarea.bottom());
- LOG("%d %d %d %d %d\n",m_hs,m_hbp,m_aw,m_hfp,m_pitch);
- LOG("%d %d %d %d\n",m_vs,m_vbp,m_al,m_vfp);
+ LOGCRTC("New Screen setup: %u x %u @ %f Hz\n", horiz_pix_total, vert_pix_total, 1 / ATTOSECONDS_TO_DOUBLE(refresh));
+ LOGCRTC("Visible Area: (%u, %u) - (%u, %u)\n", visarea.left(), visarea.top(), visarea.right(), visarea.bottom());
+ //LOGCRTC("%d %d %d %d %d\n",m_hs,m_hbp,m_aw,m_hfp,m_pitch);
+ //LOGCRTC("%d %d %d %d\n",m_vs,m_vbp,m_al,m_vfp);
if (m_m)
{
screen().configure(horiz_pix_total, vert_pix_total, visarea, refresh);
+ screen().reset_origin();
update_hsync_timer(0);
update_vsync_timer(0);
@@ -445,84 +459,129 @@ inline void upd7220_device::reset_figs_param()
{
m_figs.m_dc = 0x0000;
m_figs.m_d = 0x0008;
- m_figs.m_d1 = 0x0008;
- m_figs.m_d2 = 0x0000;
- m_figs.m_dm = 0x0000;
+ m_figs.m_d1 = 0xffff;
+ m_figs.m_d2 = 0x0008;
+ m_figs.m_dm = 0xffff;
m_figs.m_gd = 0;
+ m_figs.m_figure_type = 0;
+ m_pattern = (m_ra[8]) | (m_ra[9] << 8);
}
//-------------------------------------------------
// read_vram -
//-------------------------------------------------
+inline uint16_t upd7220_device::read_vram()
+{
+ uint16_t const data = readword(m_ead);
+ m_ead += x_dir[m_figs.m_dir] + (y_dir[m_figs.m_dir] * get_pitch());
+ m_ead &= 0x3ffff;
-inline void upd7220_device::read_vram(uint8_t type, uint8_t mod)
+ return data;
+}
+
+inline void upd7220_device::rdat(uint8_t type, uint8_t mod)
{
if (type == 1)
{
- LOG("uPD7220 invalid type 1 RDAT parameter\n");
+ LOG("invalid type 1 RDAT parameter\n");
return;
}
if (mod)
- LOG("uPD7220 RDAT used with mod = %02x?\n",mod);
+ LOG("RDAT used with mod = %02x?\n",mod);
while (m_figs.m_dc && m_fifo_ptr < (type ? 15 : 14))
{
+ uint16_t const data = read_vram();
switch(type)
{
- case 0:
- queue(readbyte(m_ead*2), 0);
- queue(readbyte(m_ead*2+1), 0);
- break;
- case 2:
- queue(readbyte(m_ead*2), 0);
- break;
- case 3:
- queue(readbyte(m_ead*2+1), 0);
- break;
+ case 0:
+ queue(data & 0xff, 0);
+ queue((data >> 8) & 0xff, 0);
+ break;
+ case 2:
+ queue(data & 0xff, 0);
+ break;
+ case 3:
+ queue((data >> 8) & 0xff, 0);
+ break;
}
m_figs.m_dc--;
- m_ead += x_dir[m_figs.m_dir] + (y_dir[m_figs.m_dir] * m_pitch);
- m_ead &= 0x3ffff;
}
if (m_figs.m_dc == 0)
reset_figs_param();
}
-
//-------------------------------------------------
// write_vram -
//-------------------------------------------------
-
-inline void upd7220_device::write_vram(uint8_t type, uint8_t mod)
+inline void upd7220_device::write_vram(uint8_t type, uint8_t mod, uint16_t data, uint16_t mask)
{
- uint16_t result;
+ uint16_t current = readword(m_ead);
- if (type == 1)
+ switch(mod & 3)
+ {
+ case 0x00: //replace
+ switch (type)
+ {
+ case 0: current = (current & (~mask)) | (data & mask); break;
+ case 2: current = (current & ~(mask & 0xff)) | (data & (mask & 0xff)); break;
+ case 3: current = (current & ~(mask & 0xff00)) | (data & (mask & 0xff00)); break;
+ }
+ break;
+ case 0x01: //complement
+ switch (type)
+ {
+ case 0: current = current ^ (data & mask); break;
+ case 2: current = current ^ (data & (mask & 0xff)); break;
+ case 3: current = current ^ (data & (mask & 0xff00)); break;
+ }
+ break;
+ case 0x02: //reset to zero
+ switch (type)
+ {
+ case 0: current = current & ~(data & mask); break;
+ case 2: current = current & ~(data & (mask & 0xff)); break;
+ case 3: current = current & ~(data & (mask & 0xff00)); break;
+ }
+ break;
+ case 0x03: //set to one
+ switch (type)
+ {
+ case 0: current = current | (data & mask); break;
+ case 2: current = current | (data & (mask & 0xff)); break;
+ case 3: current = current | (data & (mask & 0xff00)); break;
+ }
+ break;
+ }
+ writeword(m_ead, current);
+}
+
+inline void upd7220_device::wdat(uint8_t type, uint8_t mod)
+{
+ if(type == 1)
{
logerror("uPD7220 invalid type 1 WDAT parameter\n");
return;
}
- result = 0;
-
- result = m_pr[1] | (m_pr[2] << 8);
+ uint16_t result = m_pr[1] | (m_pr[2] << 8);
switch(type)
{
- case 0:
- result &= m_mask;
- break;
- case 2:
- result &= (m_mask & 0xff);
- break;
- case 3:
- result <<= 8;
- result &= (m_mask & 0xff00);
- break;
+ case 0:
+ result &= m_mask;
+ break;
+ case 2:
+ result &= (m_mask & 0xff);
+ break;
+ case 3:
+ result <<= 8;
+ result &= (m_mask & 0xff00);
+ break;
}
//if(result)
@@ -534,43 +593,8 @@ inline void upd7220_device::write_vram(uint8_t type, uint8_t mod)
for(int i = 0; i < m_figs.m_dc + 1; i++)
{
- switch(mod & 3)
- {
- case 0x00: //replace
- if(type == 0)
- writeword(m_ead*2+0, result);
- if(type == 2)
- writebyte(m_ead*2+0, result & 0xff);
- if(type == 3)
- writebyte(m_ead*2+1, result >> 8);
- break;
- case 0x01: //complement
- if(type == 0)
- writeword(m_ead*2+0, readword(m_ead*2+0) ^ result);
- if(type == 2)
- writebyte(m_ead*2+0, readbyte(m_ead*2+0) ^ (result & 0xff));
- if(type == 3)
- writebyte(m_ead*2+1, readbyte(m_ead*2+1) ^ (result >> 8));
- break;
- case 0x02: //reset to zero
- if(type == 0)
- writeword(m_ead*2+0, readword(m_ead*2+0) & ~result);
- if(type == 2)
- writebyte(m_ead*2+0, readbyte(m_ead*2+0) & ~(result & 0xff));
- if(type == 3)
- writebyte(m_ead*2+1, readbyte(m_ead*2+1) & ~(result >> 8));
- break;
- case 0x03: //set to one
- if(type == 0)
- writeword(m_ead*2+0, readword(m_ead*2+0) | result);
- if(type == 2)
- writebyte(m_ead*2+0, readbyte(m_ead*2+0) | (result & 0xff));
- if(type == 3)
- writebyte(m_ead*2+1, readbyte(m_ead*2+1) | (result >> 8));
- break;
- }
-
- m_ead += x_dir[m_figs.m_dir] + (y_dir[m_figs.m_dir] * m_pitch);
+ write_vram(type, mod, result);
+ m_ead += x_dir[m_figs.m_dir] + (y_dir[m_figs.m_dir] * get_pitch());
m_ead &= 0x3ffff;
}
}
@@ -601,6 +625,19 @@ inline void upd7220_device::get_graphics_partition(int index, uint32_t *sad, uin
*wd = BIT(m_ra[(index * 4) + 3], 7);
}
+/*
+ * experimental, for non-canonical stuff such as PC9821 PEGC
+ */
+std::tuple<u32, u16, u8> upd7220_device::get_area_partition_props(int line)
+{
+ uint32_t sad;
+ uint16_t len;
+ int im, wd;
+ // TODO: multiareas (pc9821:skinpan title)
+ get_graphics_partition(0, &sad, &len, &im, &wd);
+
+ return std::make_tuple(sad, m_pitch, im);
+}
//**************************************************************************
@@ -611,18 +648,20 @@ inline void upd7220_device::get_graphics_partition(int index, uint32_t *sad, uin
// upd7220_device - constructor
//-------------------------------------------------
-upd7220_device::upd7220_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
- device_t(mconfig, UPD7220, tag, owner, clock),
+upd7220_device::upd7220_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, type, tag, owner, clock),
device_memory_interface(mconfig, *this),
device_video_interface(mconfig, *this),
+ m_display_cb(*this),
+ m_draw_text_cb(*this),
m_write_drq(*this),
m_write_hsync(*this),
m_write_vsync(*this),
m_write_blank(*this),
+ m_pattern(0),
m_mask(0),
m_pitch(0),
m_ead(0),
- m_dad(0),
m_lad(0),
m_ra_addr(0),
m_sr(UPD7220_SR_FIFO_EMPTY),
@@ -650,7 +689,7 @@ upd7220_device::upd7220_device(const machine_config &mconfig, const char *tag, d
m_disp(0),
m_gchr(0),
m_bitmap_mod(0),
- m_space_config("videoram", ENDIANNESS_LITTLE, 16, 18, 0, address_map_constructor(FUNC(upd7220_device::upd7220_vram), this))
+ m_space_config("videoram", ENDIANNESS_LITTLE, 16, 18, -1, address_map_constructor(FUNC(upd7220_device::upd7220_vram), this))
{
for (int i = 0; i < 16; i++)
{
@@ -668,6 +707,16 @@ upd7220_device::upd7220_device(const machine_config &mconfig, const char *tag, d
memset(&m_figs, 0x00, sizeof(m_figs));
}
+upd7220_device::upd7220_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : upd7220_device(mconfig, UPD7220, tag, owner, clock)
+{
+}
+
+upd7220a_device::upd7220a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : upd7220_device(mconfig, UPD7220A, tag, owner, clock)
+{
+}
+
//-------------------------------------------------
// device_start - device-specific startup
@@ -676,18 +725,13 @@ upd7220_device::upd7220_device(const machine_config &mconfig, const char *tag, d
void upd7220_device::device_start()
{
// resolve callbacks
- m_display_cb.bind_relative_to(*owner());
- m_draw_text_cb.bind_relative_to(*owner());
-
- m_write_drq.resolve_safe();
- m_write_hsync.resolve_safe();
- m_write_vsync.resolve_safe();
- m_write_blank.resolve_safe();
+ m_display_cb.resolve_safe();
+ m_draw_text_cb.resolve_safe();
// allocate timers
- m_vsync_timer = timer_alloc(TIMER_VSYNC);
- m_hsync_timer = timer_alloc(TIMER_HSYNC);
- m_blank_timer = timer_alloc(TIMER_BLANK);
+ m_vsync_timer = timer_alloc(FUNC(upd7220_device::vsync_update), this);
+ m_hsync_timer = timer_alloc(FUNC(upd7220_device::hsync_update), this);
+ m_blank_timer = timer_alloc(FUNC(upd7220_device::blank_update), this);
// register for state saving
save_item(NAME(m_ra));
@@ -710,12 +754,29 @@ void upd7220_device::device_start()
save_item(NAME(m_ctop));
save_item(NAME(m_cbot));
save_item(NAME(m_ead));
- save_item(NAME(m_dad));
save_item(NAME(m_lad));
save_item(NAME(m_disp));
save_item(NAME(m_gchr));
+ save_item(NAME(m_pattern));
save_item(NAME(m_mask));
save_item(NAME(m_pitch));
+ save_item(NAME(m_ra_addr));
+ save_item(NAME(m_cr));
+ save_item(NAME(m_pr));
+ save_item(NAME(m_param_ptr));
+ save_item(NAME(m_fifo));
+ save_item(NAME(m_fifo_flag));
+ save_item(NAME(m_fifo_ptr));
+ save_item(NAME(m_fifo_dir));
+ save_item(NAME(m_bitmap_mod));
+ save_item(NAME(m_figs.m_dir));
+ save_item(NAME(m_figs.m_figure_type));
+ save_item(NAME(m_figs.m_dc));
+ save_item(NAME(m_figs.m_gd));
+ save_item(NAME(m_figs.m_d));
+ save_item(NAME(m_figs.m_d1));
+ save_item(NAME(m_figs.m_d2));
+ save_item(NAME(m_figs.m_dm));
}
@@ -730,58 +791,55 @@ void upd7220_device::device_reset()
//-------------------------------------------------
-// device_timer - handler timer events
+// timer events
//-------------------------------------------------
-void upd7220_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(upd7220_device::hsync_update)
{
- switch (id)
+ if (param)
{
- case TIMER_HSYNC:
- if (param)
- {
- m_sr |= UPD7220_SR_HBLANK_ACTIVE;
- }
- else
- {
- m_sr &= ~UPD7220_SR_HBLANK_ACTIVE;
- }
+ m_sr |= UPD7220_SR_HBLANK_ACTIVE;
+ }
+ else
+ {
+ m_sr &= ~UPD7220_SR_HBLANK_ACTIVE;
+ }
- m_write_hsync(param);
+ m_write_hsync(param);
- update_hsync_timer(param);
- break;
+ update_hsync_timer(param);
+}
- case TIMER_VSYNC:
- if (param)
- {
- m_sr |= UPD7220_SR_VSYNC_ACTIVE;
- }
- else
- {
- m_sr &= ~UPD7220_SR_VSYNC_ACTIVE;
- }
+TIMER_CALLBACK_MEMBER(upd7220_device::vsync_update)
+{
+ if (param)
+ {
+ m_sr |= UPD7220_SR_VSYNC_ACTIVE;
+ }
+ else
+ {
+ m_sr &= ~UPD7220_SR_VSYNC_ACTIVE;
+ }
- m_write_vsync(param);
+ m_write_vsync(param);
- update_vsync_timer(param);
- break;
+ update_vsync_timer(param);
+}
- case TIMER_BLANK:
- if (param)
- {
- m_sr |= UPD7220_SR_HBLANK_ACTIVE;
- }
- else
- {
- m_sr &= ~UPD7220_SR_HBLANK_ACTIVE;
- }
+TIMER_CALLBACK_MEMBER(upd7220_device::blank_update)
+{
+ if (param)
+ {
+ m_sr |= UPD7220_SR_HBLANK_ACTIVE;
+ }
+ else
+ {
+ m_sr &= ~UPD7220_SR_HBLANK_ACTIVE;
+ }
- m_write_blank(param);
+ m_write_blank(param);
- update_blank_timer(param);
- break;
- }
+ update_blank_timer(param);
}
@@ -789,26 +847,15 @@ void upd7220_device::device_timer(emu_timer &timer, device_timer_id id, int para
// draw_pixel -
//-------------------------------------------------
-void upd7220_device::draw_pixel(int x, int y, int xi, uint16_t tile_data)
+void upd7220_device::draw_pixel()
{
- uint32_t addr = ((y * (m_pitch << (m_figs.m_gd ? 0 : 1))) + (x >> 3)) & 0x3ffff;
- uint16_t data = readword(addr);
- uint16_t new_pixel = (tile_data & (1 << (xi & 0xf))) ? (1 << (x & 0xf)) : 0;
+ LOGDRAW("draw_pixel(): EAD=%08x MASK=%04x MOD=%02x - FIGS DIR=%02x DC=%d\n", m_ead, m_mask, m_bitmap_mod, m_figs.m_dir, m_figs.m_dc);
- switch(m_bitmap_mod)
+ for(int i = 0; i <= m_figs.m_dc; ++i)
{
- case 0: //replace
- writeword(addr, (data & ~(1 << (x & 0xf))) | new_pixel);
- break;
- case 1: //complement
- writeword(addr, data ^ new_pixel);
- break;
- case 2: //reset
- writeword(addr, data & ~new_pixel);
- break;
- case 3: //set
- writeword(addr, data | new_pixel);
- break;
+ const uint16_t pattern = get_pattern(i & 0xf);
+ write_vram(0, m_bitmap_mod, pattern, m_mask);
+ next_pixel(m_figs.m_dir);
}
}
@@ -817,219 +864,239 @@ void upd7220_device::draw_pixel(int x, int y, int xi, uint16_t tile_data)
// draw_line -
//-------------------------------------------------
-void upd7220_device::draw_line(int x, int y)
+void upd7220_device::draw_line()
{
- int xi, yi;
- int d = (m_figs.m_d & 0x2000) ? (int16_t)(m_figs.m_d | 0xe000) : m_figs.m_d;
- int d1 = (m_figs.m_d1 & 0x2000) ? (int16_t)(m_figs.m_d1 | 0xe000) : m_figs.m_d1;
- int d2 = (m_figs.m_d2 & 0x2000) ? (int16_t)(m_figs.m_d2 | 0xe000) : m_figs.m_d2;
- uint16_t pattern = (m_ra[8]) | (m_ra[9]<<8);
- const int dot_dir[4] = {1, -1, -1, 1};
+ int d = util::sext(m_figs.m_d, 14);
+ int d1 = util::sext(m_figs.m_d1, 14);
+ int d2 = util::sext(m_figs.m_d2, 14);
+ const uint8_t octant = m_figs.m_dir;
- LOG("uPD7220 line check: %d %d %02x %08x %d %d %d\n",x,y,m_figs.m_dir,m_ead,d1,m_figs.m_dc,m_bitmap_mod);
+ LOGDRAW("draw_line(): EAD=%08x MASK=%04x MOD=%02x - FIGS DIR=%02x DC=%d D=%d D1=%d D2=%d\n", m_ead, m_mask, m_bitmap_mod, m_figs.m_dir, m_figs.m_dc, d, d1, d2);
- for(yi = xi = 0; yi <= m_figs.m_dc; yi++)
+ for(int i = 0; i <= m_figs.m_dc; ++i)
{
- switch(m_figs.m_dir & 3)
+ const uint16_t pattern = get_pattern(i & 0xf);
+ write_vram(0, m_bitmap_mod, pattern, m_mask);
+ if (octant & 1)
{
- case 1:
- case 2:
- draw_pixel(yi * dot_dir[((m_figs.m_dir >> 1) + 3) & 3] + x, xi * dot_dir[m_figs.m_dir >> 1] + y, yi, pattern);
- break;
- default:
- draw_pixel(xi * dot_dir[((m_figs.m_dir >> 1) + 3) & 3] + x, yi * dot_dir[m_figs.m_dir >> 1] + y, yi, pattern);
- break;
+ m_figs.m_dir = (d < 0) ? (octant + 1) & 7 : octant;
}
- if(d > 0)
+ else
{
- xi++;
- d += d2;
+ m_figs.m_dir = (d < 0) ? octant : (octant + 1) & 7;
}
- else
- d += d1;
- }
-
- switch(m_figs.m_dir & 3)
- {
- case 1:
- case 2:
- x += yi * dot_dir[((m_figs.m_dir >> 1) + 3) & 3];
- y += xi * dot_dir[m_figs.m_dir >> 1];
- break;
- default:
- x += xi * dot_dir[((m_figs.m_dir >> 1) + 3) & 3];
- y += yi * dot_dir[m_figs.m_dir >> 1];
- break;
+ d += ((d < 0) ? d1 : d2);
+ next_pixel(m_figs.m_dir);
}
-
- m_ead = (x >> 4) + (y * (m_pitch >> m_figs.m_gd));
- m_dad = x & 0x0f;
}
+
//-------------------------------------------------
// draw_arc -
//-------------------------------------------------
-void upd7220_device::draw_arc(int x, int y)
+void upd7220_device::draw_arc()
{
- int xi = 0, err = -m_figs.m_d, d = m_figs.m_d + 1;
- uint16_t pattern = (m_ra[8]) | (m_ra[9]<<8);
- const int dot_dir[4] = {1, -1, -1, 1};
+ int err = -m_figs.m_d, d = m_figs.m_d + 1;
+
+ const uint16_t octant = m_figs.m_dir;
- LOG("uPD7220 arc check: %d %d %02x %08x %d %d %d\n",x,y,m_figs.m_dir,m_ead,m_figs.m_dm,m_figs.m_dc,m_figs.m_d);
+ LOGDRAW("draw_arc(): EAD=%08x MASK=%04x MOD=%02x - FIGS DIR=%02x DC=%d D=%d D2=%d DM=%d\n", m_ead, m_mask, m_bitmap_mod, m_figs.m_dir, m_figs.m_dc, m_figs.m_d, m_figs.m_d2, m_figs.m_dm);
- for(int yi = 0; yi <= m_figs.m_dc; yi++)
+ for (int i = 0; i <= m_figs.m_dc; ++i)
{
- if(yi >= m_figs.m_dm)
+ const uint16_t pattern = get_pattern(i % 0xf);
+ if (i >= m_figs.m_dm)
{
- switch(m_figs.m_dir & 3)
- {
- case 1:
- case 2:
- draw_pixel(yi * dot_dir[((m_figs.m_dir >> 1) + 3) & 3] + x, xi * dot_dir[m_figs.m_dir >> 1] + y, yi, pattern);
- break;
- default:
- draw_pixel(xi * dot_dir[((m_figs.m_dir >> 1) + 3) & 3] + x, yi * dot_dir[m_figs.m_dir >> 1] + y, yi, pattern);
- break;
- }
+ write_vram(0, m_bitmap_mod, pattern, m_mask);
+ }
+ if (err < 0)
+ {
+ m_figs.m_dir = (octant & 1) ? (octant + 1) & 7 : octant;
}
- if(err < 0)
- err += (yi + 1) << 1;
else
{
- xi++;
- d--;
- err += (yi - d + 1) << 1;
+ m_figs.m_dir = (octant & 1) ? octant : (octant + 1) & 7;
}
+ err += (err < 0) ? ((i + 1) << 1) : ((i - --d + 1) << 1);
+ next_pixel(m_figs.m_dir);
}
- switch(m_figs.m_dir & 3)
- {
- case 1:
- case 2:
- x += (m_figs.m_dc + 1) * dot_dir[((m_figs.m_dir >> 1) + 3) & 3];
- break;
- default:
- y += (m_figs.m_dc + 1) * dot_dir[m_figs.m_dir >> 1];
- break;
- }
-
- m_ead = (x >> 4) + (y * (m_pitch >> m_figs.m_gd));
- m_dad = x & 0x0f;
}
+
//-------------------------------------------------
// draw_rectangle -
//-------------------------------------------------
-void upd7220_device::draw_rectangle(int x, int y)
+void upd7220_device::draw_rectangle()
{
- int i;
- const int rect_x_dir[8] = { 0, 1, 0,-1, 1, 1,-1,-1 };
- const int rect_y_dir[8] = { 1, 0,-1, 0, 1,-1,-1, 1 };
- uint8_t rect_type,rect_dir;
- uint16_t pattern = (m_ra[8]) | (m_ra[9]<<8);
+ assert(m_figs.m_dc == 3);
- LOG("uPD7220 rectangle check: %d %d %02x %08x\n",x,y,m_figs.m_dir,m_ead);
+ LOGDRAW("draw_rectangle(): EAD=%08x MASK=%04x MOD=%02x - FIGS DIR=%02x DC=%d D=%d D2=%d\n",m_ead, m_mask, m_bitmap_mod, m_figs.m_dir, m_figs.m_dc, m_figs.m_d, m_figs.m_d2);
- rect_type = (m_figs.m_dir & 1) << 2;
- rect_dir = rect_type | (((m_figs.m_dir >> 1) + 0) & 3);
-
- for(i = 0;i < m_figs.m_d;i++)
+ for (int i = 0; i <= m_figs.m_dc; ++i)
{
- draw_pixel(x,y,i,pattern);
- x+=rect_x_dir[rect_dir];
- y+=rect_y_dir[rect_dir];
+ const uint16_t dist = (i & 1 ? m_figs.m_d2 : m_figs.m_d);
+ for (int j = 0; j < dist; ++j)
+ {
+ const uint16_t pattern = get_pattern(j & 0xf);
+ write_vram(0, m_bitmap_mod, pattern, m_mask);
+ if (i > 0 && j == 0)
+ m_figs.m_dir = (m_figs.m_dir + 2) & 7;
+ next_pixel(m_figs.m_dir);
+ }
+
}
+}
- rect_dir = rect_type | (((m_figs.m_dir >> 1) + 1) & 3);
- for(i = 0;i < m_figs.m_d2;i++)
- {
- draw_pixel(x,y,i,pattern);
- x+=rect_x_dir[rect_dir];
- y+=rect_y_dir[rect_dir];
- }
+//-------------------------------------------------
+// draw_char -
+//-------------------------------------------------
- rect_dir = rect_type | (((m_figs.m_dir >> 1) + 2) & 3);
+void upd7220_device::draw_char()
+{
+ const int8_t dir_change[2][4] = {
+ {2, 2, -2, -2},
+ {1, 3, -3, -1}
+ };
+ const uint8_t type = (m_figs.m_figure_type & 0x10) >> 4;
- for(i = 0;i < m_figs.m_d;i++)
+ LOGDRAW("draw_char(): EAD=%08x MASK=%04x MOD=%02x DIR=%02x D=%d DC=%d FIGURE=%02x\n",m_ead,m_mask,m_bitmap_mod,m_figs.m_dir,m_figs.m_d,m_figs.m_dc,m_figs.m_figure_type);
+
+ for (int i = 0, di = 0; i < (m_figs.m_dc + 1); ++i)
{
- draw_pixel(x,y,i,pattern);
- x+=rect_x_dir[rect_dir];
- y+=rect_y_dir[rect_dir];
+ m_pattern = (m_ra[15 - (i & 7)] << 8) | m_ra[15 - (i & 7)];
+ for (int zdc = 0; zdc <= m_gchr; ++zdc, ++di)
+ {
+ for (int j = 0; j < m_figs.m_d; ++j)
+ {
+ const uint16_t pattern = (di % 2) ? get_pattern(15-(j & 0xf)) : get_pattern((j & 0xf));
+ for (int zd = 0; zd <= m_gchr; ++zd)
+ {
+ write_vram(0, m_bitmap_mod, pattern, m_mask);
+
+ if (j != (m_figs.m_d - 1) || zd != m_gchr)
+ next_pixel(m_figs.m_dir);
+ }
+ }
+ m_figs.m_dir = (((uint16_t)m_figs.m_dir + dir_change[type][(di % 2) << 1]) & 7);
+ next_pixel(m_figs.m_dir);
+ m_figs.m_dir = (((uint16_t)m_figs.m_dir + dir_change[type][((di % 2) << 1)+1]) & 7);
+ }
}
+}
- rect_dir = rect_type | (((m_figs.m_dir >> 1) + 3) & 3);
- for(i = 0;i < m_figs.m_d2;i++)
- {
- draw_pixel(x,y,i,pattern);
- x+=rect_x_dir[rect_dir];
- y+=rect_y_dir[rect_dir];
- }
+//-------------------------------------------------
+// helper functions used to rotate a uint16_t
+//-------------------------------------------------
- m_ead = (x >> 4) + (y * (m_pitch >> m_figs.m_gd));
- m_dad = x & 0x0f;
+static constexpr uint16_t rotate_right(uint16_t value)
+{
+ return (value>>1) | (value<<( (-1) & 0x0f ));
+}
+static constexpr uint16_t rotate_left(uint16_t value)
+{
+ return (value<<1) | (value>>( (-1) & 0x0f ));
}
//-------------------------------------------------
-// draw_char -
+// get_pitch -
//-------------------------------------------------
-void upd7220_device::draw_char(int x, int y)
+uint16_t upd7220_device::get_pitch()
{
- int isize,psize;
- uint16_t tile_data;
+ bool mixed = ((m_mode & UPD7220_MODE_DISPLAY_MASK) == UPD7220_MODE_DISPLAY_MIXED);
+
+ if (mixed)
+ return m_pitch >> m_figs.m_gd;
+
+ return m_pitch;
+}
+
- LOG("uPD7220 char check: %d %d %02x %08x %d %d %02x\n",x,y,m_figs.m_dir,m_ead,m_figs.m_d,m_figs.m_dc,m_figs.m_figure_type);
+//-------------------------------------------------
+// get_pattern -
+//-------------------------------------------------
- /* QX10 may require upper bits for psize, VT240 requires the opposite */
- isize = m_figs.m_d;
- psize = m_figs.m_dc + 1;
+uint16_t upd7220_device::get_pattern(uint8_t cycle)
+{
+ bool mixed = ((m_mode & UPD7220_MODE_DISPLAY_MASK) == UPD7220_MODE_DISPLAY_MIXED);
+ bool graphics = ((m_mode & UPD7220_MODE_DISPLAY_MASK) == UPD7220_MODE_DISPLAY_GRAPHICS);
- for(int pi = 0; pi < psize; pi++)
+ if ((mixed && m_figs.m_gd) || graphics)
{
- tile_data = (m_ra[((psize-1-pi) & 7) | 8] << 8) | m_ra[((psize-1-pi) & 7) | 8];
- for(int pz = 0; pz <= m_gchr; pz++)
+ return ((m_pattern >> (cycle & 0xf)) & 1) * 0xffff;
+ }
+ return m_pattern;
+}
+
+
+//-------------------------------------------------
+// next_pixel -
+//-------------------------------------------------
+
+void upd7220_device::next_pixel(int direction)
+{
+ switch(direction & 7)
+ {
+ case 0:
+ m_ead += get_pitch();
+ break;
+ case 1:
+ m_ead += get_pitch();
+ if (m_mask & 0x8000)
{
- int ii = 0, curpixel = 0;
- if(pi & 1)
- {
- ii = isize - 1;
- curpixel = (isize * (m_gchr + 1)) - 1;
- }
- while(pi & 1 ? ii >= 0 : ii < isize)
- {
- for(int iz = 0; iz <= m_gchr; iz++)
- {
- draw_pixel(x + (curpixel * x_dir[m_figs.m_dir]), y + (curpixel * y_dir[m_figs.m_dir]), ii, tile_data);
- if(pi & 1)
- curpixel--;
- else
- curpixel++;
- }
- if(pi & 1)
- ii--;
- else
- ii++;
- }
- if(m_figs.m_figure_type == 2)
- {
- x += x_dir[(m_figs.m_dir + 2) & 7];
- y += y_dir[(m_figs.m_dir + 2) & 7];
- }
- else
- {
- x += x_dir[(m_figs.m_dir + 1) & 7];
- y += y_dir[(m_figs.m_dir + 1) & 7];
- }
+ m_ead += 1;
+ }
+ m_mask = rotate_left(m_mask);
+ break;
+ case 2:
+ if (m_mask & 0x8000)
+ {
+ m_ead += 1;
+ }
+ m_mask = rotate_left(m_mask);
+ break;
+ case 3:
+ m_ead -= get_pitch();
+ if (m_mask & 0x8000)
+ {
+ m_ead += 1;
}
+ m_mask = rotate_left(m_mask);
+ break;
+ case 4:
+ m_ead -= get_pitch();
+ break;
+ case 5:
+ m_ead -= get_pitch();
+ if (m_mask & 0x1)
+ {
+ m_ead -= 1;
+ }
+ m_mask = rotate_right(m_mask);
+ break;
+ case 6:
+ if (m_mask & 0x1)
+ {
+ m_ead -= 1;
+ }
+ m_mask = rotate_right(m_mask);
+ break;
+ case 7:
+ m_ead += get_pitch();
+ if (m_mask & 0x1)
+ {
+ m_ead -= 1;
+ }
+ m_mask = rotate_right(m_mask);
+ break;
}
-
- m_ead = (x >> 4) + (y * (m_pitch >> m_figs.m_gd));
- m_dad = (x & 0xf);
+ m_ead &= 0x3ffff;
}
@@ -1056,13 +1123,12 @@ int upd7220_device::translate_command(uint8_t data)
case UPD7220_COMMAND_CURD: command = COMMAND_CURD; break;
case UPD7220_COMMAND_LPRD: command = COMMAND_LPRD; break;
case UPD7220_COMMAND_5A: command = COMMAND_5A; break;
- case UPD7220_COMMAND_05: command = COMMAND_05; break;
default:
switch (data & 0xfe)
{
case UPD7220_COMMAND_SYNC: command = COMMAND_SYNC; break;
case UPD7220_COMMAND_VSYNC: command = COMMAND_VSYNC; break;
- case UPD7220_COMMAND_BCTRL: command = COMMAND_BCTRL; break;
+ case UPD7220_COMMAND_BLANK: command = COMMAND_BLANK; break;
default:
switch (data & 0xf0)
{
@@ -1082,6 +1148,20 @@ int upd7220_device::translate_command(uint8_t data)
return command;
}
+int upd7220a_device::translate_command(uint8_t data)
+{
+ int command = upd7220_device::translate_command(data);
+
+ switch (data)
+ {
+ case UPD7220_COMMAND_RESET2: command = COMMAND_RESET2; break;
+ case UPD7220_COMMAND_RESET3: command = COMMAND_RESET3; break;
+ case UPD7220_COMMAND_BLANK2: command = COMMAND_BLANK2; break;
+ }
+
+ return command;
+}
+
//-------------------------------------------------
// process_fifo -
@@ -1091,22 +1171,27 @@ void upd7220_device::process_fifo()
{
uint8_t data;
int flag;
- uint16_t eff_pitch = m_pitch >> m_figs.m_gd;
+ int cr;
dequeue(&data, &flag);
if (flag == FIFO_COMMAND)
{
- m_cr = data;
- m_param_ptr = 1;
+ cr = translate_command(data);
+ if (cr != COMMAND_BLANK) // workaround for Rainbow 100 Windows 1.03, needs verification
+ {
+ m_cr = data;
+ m_param_ptr = 1;
+ }
}
else
{
+ cr = translate_command(m_cr);
m_pr[m_param_ptr] = data;
m_param_ptr++;
}
- switch (translate_command(m_cr))
+ switch (cr)
{
case COMMAND_INVALID:
logerror("uPD7220 Invalid Command Byte %02x\n", m_cr);
@@ -1118,17 +1203,29 @@ void upd7220_device::process_fifo()
break;
case COMMAND_RESET: /* reset */
+ case COMMAND_RESET2:
+ case COMMAND_RESET3:
switch (m_param_ptr)
{
- case 0:
- LOG("uPD7220 RESET\n");
-
- m_de = 0;
- m_ra[0] = m_ra[1] = m_ra[2] = 0;
- m_ra[3] = 0x19;
+ case 1:
+ LOGCMD("RESET %02x\n", cr);
+
+ if (cr != COMMAND_RESET3)
+ m_de = 0;
+ // NOTE: a reset doesn't touch anything belonging to parameters, as stated in docs.
+ // pc9801:mightyhd won't program sad/len but just issue a reset after BIOS
+ // (which originally sets len = 0x1ff)
+ // with this on, it will len = 400 lines, repeating the bottommost two rows in a 432 setup.
+ //m_ra[0] = m_ra[1] = m_ra[2] = 0;
+ //m_ra[3] = 0x19;
m_ead = 0;
- m_dad = 0;
+ // TODO: very unlikely, should be 0xffff assuming it's even touched ...
m_mask = 0;
+ // FIFO, Command Processor and internal counters are cleared by this
+ // - pc9801rs BIOS starts up a DMAW command that spindiz2 will dislike during its boot sequences
+ m_sr &= ~UPD7220_SR_DRAWING_IN_PROGRESS;
+ fifo_clear();
+ stop_dma();
break;
case 9:
@@ -1144,16 +1241,15 @@ void upd7220_device::process_fifo()
m_pitch = m_aw;
- LOG("uPD7220 Mode: %02x\n", m_mode);
- LOG("uPD7220 AW: %u\n", m_aw);
- LOG("uPD7220 HS: %u\n", m_hs);
- LOG("uPD7220 VS: %u\n", m_vs);
- LOG("uPD7220 HFP: %u\n", m_hfp);
- LOG("uPD7220 HBP: %u\n", m_hbp);
- LOG("uPD7220 VFP: %u\n", m_vfp);
- LOG("uPD7220 AL: %u\n", m_al);
- LOG("uPD7220 VBP: %u\n", m_vbp);
- LOG("uPD7220 PITCH: %u\n", m_pitch);
+ if (type() == UPD7220A)
+ {
+ m_pitch = ((m_pr[5] & 0x40) << 2) | (m_pitch & 0xff);
+ m_al += (m_pr[6] >> 6) & 1;
+ }
+
+ LOGCMD("- Mode: %02x\n", m_mode);
+ LOGCMD("- HS=%u HBP=%u AW=%u HFP=%u PITCH=%u\n", m_hs, m_hbp, m_aw, m_hfp, m_pitch);
+ LOGCMD("- VS=%u VBP=%u AL=%u VFP=%u\n", m_vs, m_vbp, m_al, m_vfp);
recompute_parameters();
break;
@@ -1161,6 +1257,13 @@ void upd7220_device::process_fifo()
break;
case COMMAND_SYNC: /* sync format specify */
+ if (flag == FIFO_COMMAND)
+ {
+ m_de = m_cr & 1;
+ LOGCMD2("SYNC %u\n", m_de);
+ }
+
+ // TODO: merge implementation with above
if (m_param_ptr == 9)
{
m_mode = m_pr[1];
@@ -1175,16 +1278,15 @@ void upd7220_device::process_fifo()
m_pitch = m_aw;
- LOG("uPD7220 Mode: %02x\n", m_mode);
- LOG("uPD7220 AW: %u\n", m_aw);
- LOG("uPD7220 HS: %u\n", m_hs);
- LOG("uPD7220 VS: %u\n", m_vs);
- LOG("uPD7220 HFP: %u\n", m_hfp);
- LOG("uPD7220 HBP: %u\n", m_hbp);
- LOG("uPD7220 VFP: %u\n", m_vfp);
- LOG("uPD7220 AL: %u\n", m_al);
- LOG("uPD7220 VBP: %u\n", m_vbp);
- LOG("uPD7220 PITCH: %u\n", m_pitch);
+ if (type() == UPD7220A)
+ {
+ m_pitch = ((m_pr[5] & 0x40) << 2) | (m_pitch & 0xff);
+ m_al += (m_pr[6] >> 6) & 1;
+ }
+
+ LOGCMD("- Mode: %02x\n", m_mode);
+ LOGCMD("- HS=%u HBP=%u AW=%u HFP=%u PITCH=%u\n", m_hs, m_hbp, m_aw, m_hfp, m_pitch);
+ LOGCMD("- VS=%u VBP=%u AL=%u VFP=%u\n", m_vs, m_vbp, m_al, m_vfp);
recompute_parameters();
}
@@ -1193,55 +1295,54 @@ void upd7220_device::process_fifo()
case COMMAND_VSYNC: /* vertical sync mode */
m_m = m_cr & 0x01;
- LOG("uPD7220 M: %u\n", m_m);
+ LOGCMD("VSYNC M=%u\n", m_m);
recompute_parameters();
break;
case COMMAND_CCHAR: /* cursor & character characteristics */
- if(m_param_ptr == 2)
+ switch (m_param_ptr)
{
+ case 2:
m_lr = (m_pr[1] & 0x1f) + 1;
m_dc = BIT(m_pr[1], 7);
- LOG("uPD7220 LR: %u\n", m_lr);
- LOG("uPD7220 DC: %u\n", m_dc);
- }
+ LOGCMD("CCHAR LR=%u DC=%u\n", m_lr, m_dc);
+ break;
- if(m_param_ptr == 3)
- {
+ case 3:
m_ctop = m_pr[2] & 0x1f;
m_sc = BIT(m_pr[2], 5);
m_br = (m_pr[2] >> 6); /* guess, assume that blink rate clears upper bits (if any) */
- LOG("uPD7220 CTOP: %u\n", m_ctop);
- LOG("uPD7220 SC: %u\n", m_sc);
- }
+ LOGCMD("- CTOP=%u SC=%u\n", m_ctop, m_sc);
+ break;
- if(m_param_ptr == 4)
- {
+ case 4:
m_br = ((m_pr[3] & 0x07) << 2) | (m_pr[2] >> 6);
m_cbot = m_pr[3] >> 3;
- LOG("uPD7220 BR: %u\n", m_br);
- LOG("uPD7220 CBOT: %u\n", m_cbot);
+ LOGCMD("- BR=%u CBOT=%u\n", m_br, m_cbot);
+ break;
}
break;
case COMMAND_START: /* start display & end idle mode */
m_de = 1;
- //LOG("uPD7220 '%s' DE: 1\n");
+ LOGCMD2("START\n");
break;
- case COMMAND_05:
+ case COMMAND_BLANK2:
m_de = 0;
+ LOGCMD2("BLANK2\n");
+
break;
- case COMMAND_BCTRL: /* display blanking control */
- m_de = m_cr & 0x01;
+ case COMMAND_BLANK: /* display blanking control */
+ m_de = data & 0x01;
- //LOG("uPD7220 DE: %u\n", m_de);
+ LOGCMD2("BLANK %u\n", m_de);
break;
case COMMAND_ZOOM: /* zoom factors specify */
@@ -1250,8 +1351,7 @@ void upd7220_device::process_fifo()
m_gchr = m_pr[1] & 0x0f;
m_disp = m_pr[1] >> 4;
- LOG("uPD7220 GCHR: %01x\n", m_gchr);
- LOG("uPD7220 DISP: %01x\n", m_disp);
+ LOGCMD("ZOOM GCHR=%01x DISP=%01x\n", m_gchr, m_disp);
}
break;
@@ -1262,12 +1362,12 @@ void upd7220_device::process_fifo()
m_ead = (upper_addr << 16) | (m_pr[2] << 8) | m_pr[1];
- LOG("uPD7220 EAD: %06x\n", m_ead);
+ LOGCMD("CURS EAD: %06x\n", m_ead);
if(m_param_ptr == 4)
{
- m_dad = m_pr[3] >> 4;
- LOG("uPD7220 DAD: %01x\n", m_dad);
+ m_mask = 1 << ((m_pr[3] >> 4) & 0x0f);
+ LOGCMD("- MASK: %04x\n", m_mask);
}
}
break;
@@ -1281,8 +1381,13 @@ void upd7220_device::process_fifo()
{
if (m_ra_addr < 16)
{
- LOG("uPD7220 RA%u: %02x\n", m_ra_addr, data);
+ LOGCMD("PRAM RA%u: %02x\n", m_ra_addr, data);
+ switch (m_ra_addr)
+ {
+ case 8: m_pattern = (m_pattern & 0xff00) | data; break;
+ case 9: m_pattern = (m_pattern & 0x00ff) | (data << 8); break;
+ }
m_ra[m_ra_addr] = data;
m_ra_addr++;
}
@@ -1292,11 +1397,21 @@ void upd7220_device::process_fifo()
break;
case COMMAND_PITCH: /* pitch specification */
- if (flag == FIFO_PARAMETER)
+ // pc9801:burai writes a spurious extra value during intro, effectively ignored
+ // (only first value matters)
+ if (flag == FIFO_PARAMETER && m_param_ptr == 2)
{
- m_pitch = data;
+ m_pitch = (m_pitch & 0x100) | data;
+
+ if (m_pitch < 2)
+ {
+ // TODO: a pitch of zero will lead to a MAME crash in draw_graphics_line
+ // Coerce a fail-safe minimum, what should really happen is to be verified ...
+ popmessage("%s pitch == 0!", this->tag());
+ m_pitch = 2;
+ }
- LOG("uPD7220 PITCH: %u\n", m_pitch);
+ LOGCMD("PITCH %u\n", m_pitch);
}
break;
@@ -1305,10 +1420,23 @@ void upd7220_device::process_fifo()
if (m_param_ptr == 3 || (m_param_ptr == 2 && m_cr & 0x10))
{
- LOG("%02x = %02x %02x (%c) %06x %04x\n",m_cr,m_pr[2],m_pr[1],m_pr[1]?m_pr[1]:' ',m_ead,m_figs.m_dc);
+ m_pattern = (m_pattern & 0xff00) | m_pr[1];
+ if (m_param_ptr == 3)
+ m_pattern = (m_pattern & 0xff) | (m_pr[2] << 8);
+ LOGCMD3("WDAT PATTERN=%04x\n", m_pattern);
+ if (m_figs.m_figure_type)
+ break;
+ LOGCMD3("- CR=%02x (%02x %02x) (%c) EAD=%06x - FIGS DC=%04x\n"
+ , m_cr
+ , m_pr[2]
+ , m_pr[1]
+ , m_pr[1] ? m_pr[1]:' '
+ , m_ead
+ , m_figs.m_dc
+ );
fifo_set_direction(FIFO_WRITE);
- write_vram((m_cr & 0x18) >> 3,m_cr & 3);
+ wdat((m_cr & 0x18) >> 3,m_cr & 3);
reset_figs_param();
m_param_ptr = 1;
}
@@ -1319,95 +1447,113 @@ void upd7220_device::process_fifo()
{
m_mask = (m_pr[2] << 8) | m_pr[1];
- LOG("uPD7220 MASK: %04x\n", m_mask);
+ LOGCMD("MASK %04x\n", m_mask);
}
break;
case COMMAND_FIGS: /* figure drawing parameters specify */
- if (m_param_ptr == 2)
+ switch (m_param_ptr)
{
+ case 2:
m_figs.m_dir = m_pr[1] & 0x7;
m_figs.m_figure_type = (m_pr[1] & 0xf8) >> 3;
+ LOGCMD("FIGS DIR=%02x FIGURE=%02x\n", m_figs.m_dir, m_figs.m_figure_type);
//if(m_figs.m_dir != 2)
// printf("DIR %02x\n",m_pr[1]);
- }
+ break;
- // the Decision Mate V during start-up test upload only 2 params before execute the
- // RDAT command, so I assume this is the expected behaviour, but this needs to be verified.
- if (m_param_ptr == 3)
+ // the Decision Mate V during start-up test upload only 2 params before execute the
+ // RDAT command, so I assume this is the expected behaviour, but this needs to be verified.
+ case 3:
m_figs.m_dc = (m_pr[2]) | (m_figs.m_dc & 0x3f00);
+ LOGCMD("- DC=%04x (*)\n", m_figs.m_dc);
+ break;
- if (m_param_ptr == 4)
- {
+ case 4:
m_figs.m_dc = (m_pr[2]) | ((m_pr[3] & 0x3f) << 8);
m_figs.m_gd = (m_pr[3] & 0x40) && ((m_mode & UPD7220_MODE_DISPLAY_MASK) == UPD7220_MODE_DISPLAY_MIXED);
- }
+ LOGCMD("- DC=%04x\n", m_figs.m_dc);
+ LOGCMD("- GD=%02x\n", m_figs.m_gd);
+ break;
- if (m_param_ptr == 6)
+ case 6:
m_figs.m_d = (m_pr[4]) | ((m_pr[5] & 0x3f) << 8);
+ LOGCMD("- D=%04x\n", m_figs.m_d);
+ break;
- if (m_param_ptr == 8)
+ case 8:
m_figs.m_d2 = (m_pr[6]) | ((m_pr[7] & 0x3f) << 8);
+ LOGCMD("- D2=%04x\n", m_figs.m_d2);
+ break;
- if (m_param_ptr == 10)
+ case 10:
m_figs.m_d1 = (m_pr[8]) | ((m_pr[9] & 0x3f) << 8);
+ LOGCMD("- D1=%04x\n", m_figs.m_d1);
+ break;
- if (m_param_ptr == 12)
+ case 12:
m_figs.m_dm = (m_pr[10]) | ((m_pr[11] & 0x3f) << 8);
-
+ LOGCMD("- DM=%04x\n", m_figs.m_dm);
+ break;
+ }
break;
case COMMAND_FIGD: /* figure draw start */
- if(m_figs.m_figure_type == 0)
- draw_pixel(((m_ead % eff_pitch) << 4) | (m_dad & 0xf),(m_ead / eff_pitch),m_dad,(m_ra[8]) | (m_ra[9]<<8));
- else if(m_figs.m_figure_type == 1)
- draw_line(((m_ead % eff_pitch) << 4) | (m_dad & 0xf),(m_ead / eff_pitch));
- else if(m_figs.m_figure_type == 4)
- draw_arc(((m_ead % eff_pitch) << 4) | (m_dad & 0xf),(m_ead / eff_pitch));
- else if(m_figs.m_figure_type == 8)
- draw_rectangle(((m_ead % eff_pitch) << 4) | (m_dad & 0xf),(m_ead / eff_pitch));
- else
- logerror("uPD7220 Unimplemented command FIGD %02x\n", m_figs.m_figure_type);
-
+ LOGCMD("FIGD %u\n", m_figs.m_figure_type);
+ switch (m_figs.m_figure_type)
+ {
+ case 0: draw_pixel(); break;
+ case 1: draw_line(); break;
+ case 4: draw_arc(); break;
+ case 8: draw_rectangle(); break;
+ default:
+ popmessage("%s Unimplemented command FIGD %02x\n", this->tag(), m_figs.m_figure_type);
+ break;
+ }
reset_figs_param();
m_sr |= UPD7220_SR_DRAWING_IN_PROGRESS;
break;
case COMMAND_GCHRD: /* graphics character draw and area filling start */
+ LOGCMD("GCHRD %u\n", m_figs.m_figure_type);
+
if((m_figs.m_figure_type & 0xf) == 2)
- draw_char(((m_ead % eff_pitch) << 4) | (m_dad & 0xf),(m_ead / eff_pitch));
+ draw_char();
else
- logerror("uPD7220 Unimplemented command GCHRD %02x\n", m_figs.m_figure_type);
+ popmessage("%s Unimplemented command GCHRD %02x\n", this->tag(), m_figs.m_figure_type);
reset_figs_param();
m_sr |= UPD7220_SR_DRAWING_IN_PROGRESS;
break;
case COMMAND_RDAT: /* read data from display memory */
+ LOGCMD3("RDAT %06x %02x\n", m_ead, m_cr);
+
fifo_set_direction(FIFO_READ);
- read_vram((m_cr & 0x18) >> 3,m_cr & 3);
+ rdat((m_cr & 0x18) >> 3,m_cr & 3);
m_sr |= UPD7220_SR_DATA_READY;
break;
case COMMAND_CURD: /* cursor address read */
- {
- uint16_t dad = 1 << m_dad;
+ LOGCMD3("CURD %06x\n", m_ead, m_mask);
+
fifo_set_direction(FIFO_READ);
queue(m_ead & 0xff, 0);
queue((m_ead >> 8) & 0xff, 0);
queue(m_ead >> 16, 0);
- queue(dad & 0xff, 0);
- queue(dad >> 8, 0);
+ queue(m_mask & 0xff, 0);
+ queue(m_mask >> 8, 0);
m_sr |= UPD7220_SR_DATA_READY;
break;
- }
case COMMAND_LPRD: /* light pen address read */
+ LOGCMD3("LPRD %06x\n", m_lad);
+
fifo_set_direction(FIFO_READ);
queue(m_lad & 0xff, 0);
@@ -1419,11 +1565,19 @@ void upd7220_device::process_fifo()
break;
case COMMAND_DMAR: /* DMA read request */
- logerror("uPD7220 Unimplemented command DMAR\n");
+ LOGCMD4("DMAR CR=%02x DC=%d D=%d\n", m_cr, m_figs.m_dc, m_figs.m_d);
+ m_dma_type = (m_cr >> 3) & 3;
+ m_dma_mod = m_cr & 3;
+ m_dma_transfer_length = (m_figs.m_dc + 1) * (m_figs.m_d + 2);
+ start_dma();
break;
case COMMAND_DMAW: /* DMA write request */
- logerror("uPD7220 Unimplemented command DMAW\n");
+ LOGCMD4("DMAW CR=%02x DC=%d D=%d\n", m_cr, m_figs.m_dc, m_figs.m_d);
+ m_dma_type = (m_cr >> 3) & 3;
+ m_dma_mod = m_cr & 3;
+ m_dma_transfer_length = (m_figs.m_dc + 1) * (m_figs.m_d + 1);
+ start_dma();
break;
}
}
@@ -1438,7 +1592,7 @@ void upd7220_device::continue_command()
// continue RDAT command when data to read are larger than the FIFO (a5105 and dmv text scrolling)
if (m_figs.m_dc && translate_command(m_cr) == COMMAND_RDAT)
{
- read_vram((m_cr & 0x18) >> 3, m_cr & 3);
+ rdat((m_cr & 0x18) >> 3, m_cr & 3);
m_sr |= UPD7220_SR_DATA_READY;
}
}
@@ -1468,7 +1622,6 @@ uint8_t upd7220_device::read(offs_t offset)
/* TODO: timing of these */
m_sr &= ~UPD7220_SR_DRAWING_IN_PROGRESS;
- m_sr &= ~UPD7220_SR_DMA_EXECUTE;
}
return data;
@@ -1504,7 +1657,36 @@ void upd7220_device::write(offs_t offset, uint8_t data)
uint8_t upd7220_device::dack_r()
{
- return 0;
+ uint8_t result = 0;
+ switch(m_dma_type)
+ {
+ case 0:
+ if (m_dma_transfer_length % 2 == 0)
+ {
+ m_dma_data = read_vram();
+ result = m_dma_data & 0xff;
+ }
+ else
+ {
+ result = (m_dma_data >> 8) & 0xff;
+ }
+ break;
+ case 2:
+ m_dma_data = read_vram();
+ result = m_dma_data & 0xff;
+ break;
+ case 3:
+ m_dma_data = read_vram();
+ result = (m_dma_data >> 8) & 0xff;
+ break;
+ default:
+ logerror("uPD7220 Invalid DMA Transfer Type\n");
+ }
+ if (--m_dma_transfer_length == 0)
+ {
+ stop_dma();
+ }
+ return result;
}
@@ -1514,6 +1696,59 @@ uint8_t upd7220_device::dack_r()
void upd7220_device::dack_w(uint8_t data)
{
+ switch(m_dma_type)
+ {
+ case 0:
+ if (m_dma_transfer_length % 2)
+ {
+ m_dma_data = ((m_dma_data & 0xff) | data << 8) & m_mask;
+ write_vram(m_dma_type, m_dma_mod, m_dma_data);
+ m_ead += x_dir[m_figs.m_dir] + (y_dir[m_figs.m_dir] * get_pitch());
+ m_ead &= 0x3ffff;
+ }
+ else
+ {
+ m_dma_data = (m_dma_data & 0xff00) | data;
+ }
+ break;
+ case 2:
+ m_dma_data = data & (m_mask & 0xff);
+ write_vram(m_dma_type, m_dma_mod, m_dma_data);
+ m_ead += x_dir[m_figs.m_dir] + (y_dir[m_figs.m_dir] * get_pitch());
+ m_ead &= 0x3ffff;
+ break;
+ case 3:
+ m_dma_data = (data << 8) & (m_mask & 0xff00);
+ write_vram(m_dma_type, m_dma_mod, m_dma_data);
+ m_ead += x_dir[m_figs.m_dir] + (y_dir[m_figs.m_dir] * get_pitch());
+ m_ead &= 0x3ffff;
+ break;
+ default:
+ logerror("uPD7220 Invalid DMA Transfer Type\n");
+ }
+ if (--m_dma_transfer_length == 0)
+ {
+ stop_dma();
+ }
+}
+
+void upd7220_device::start_dma()
+{
+ if ((m_sr & UPD7220_SR_DMA_EXECUTE) == 0)
+ {
+ m_write_drq(ASSERT_LINE);
+ m_sr |= UPD7220_SR_DMA_EXECUTE;
+ }
+}
+
+void upd7220_device::stop_dma()
+{
+ if ((m_sr & UPD7220_SR_DMA_EXECUTE) == UPD7220_SR_DMA_EXECUTE)
+ {
+ m_write_drq(CLEAR_LINE);
+ m_sr &= ~UPD7220_SR_DMA_EXECUTE;
+ reset_figs_param();
+ }
}
@@ -1521,7 +1756,7 @@ void upd7220_device::dack_w(uint8_t data)
// ext_sync_w -
//-------------------------------------------------
-WRITE_LINE_MEMBER( upd7220_device::ext_sync_w )
+void upd7220_device::ext_sync_w(int state)
{
//LOG("uPD7220 External Synchronization: %u\n", state);
@@ -1540,7 +1775,7 @@ WRITE_LINE_MEMBER( upd7220_device::ext_sync_w )
// ext_sync_w -
//-------------------------------------------------
-WRITE_LINE_MEMBER( upd7220_device::lpen_w )
+void upd7220_device::lpen_w(int state)
{
/* only if 2 rising edges on the lpen input occur at the same
point during successive video fields are the pulses accepted */
@@ -1562,21 +1797,20 @@ WRITE_LINE_MEMBER( upd7220_device::lpen_w )
void upd7220_device::update_text(bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- uint32_t addr, sad;
+ uint32_t sad;
uint16_t len;
int im, wd;
- int y, sy = 0;
+ int sy = 0;
for (int area = 0; area < 4; area++)
{
get_text_partition(area, &sad, &len, &im, &wd);
+ int y;
for (y = sy; y < sy + len; y++)
{
- addr = sad + (y * m_pitch);
-
- if (!m_draw_text_cb.isnull())
- m_draw_text_cb(bitmap, addr, (y * m_lr) + m_vbp, wd, m_pitch, m_lr, m_dc, m_ead);
+ uint32_t const addr = sad + (y * m_pitch);
+ m_draw_text_cb(bitmap, addr, (y * m_lr) + m_vbp, wd, m_pitch, m_lr, m_dc, m_ead, m_ctop, m_cbot);
}
sy = y + 1;
@@ -1588,16 +1822,17 @@ void upd7220_device::update_text(bitmap_rgb32 &bitmap, const rectangle &cliprect
// draw_graphics_line -
//-------------------------------------------------
-void upd7220_device::draw_graphics_line(bitmap_rgb32 &bitmap, uint32_t addr, int y, int wd, int pitch)
+// TODO: merge with update_graphics
+void upd7220_device::draw_graphics_line(bitmap_rgb32 &bitmap, uint32_t addr, int y, int wd, int mixed)
{
- int sx, al = bitmap.cliprect().height();
+ int al = bitmap.cliprect().height();
+ int aw = m_aw >> mixed;
+ int pitch = m_pitch >> mixed;
- for (sx = 0; sx < pitch; sx++)
+ for (int sx = 0; sx < aw; sx++)
{
- if((sx << 4) < m_aw * 16 && y < al)
- m_display_cb(bitmap, y, sx << 4, addr);
-
- addr+= (wd + 1) * 2;
+ if(sx < m_aw && y < al)
+ m_display_cb(bitmap, y, sx << 4, addr + (wd + 1) * (sx % pitch));
}
}
@@ -1608,58 +1843,79 @@ void upd7220_device::draw_graphics_line(bitmap_rgb32 &bitmap, uint32_t addr, int
void upd7220_device::update_graphics(bitmap_rgb32 &bitmap, const rectangle &cliprect, int force_bitmap)
{
- uint32_t addr, sad;
+ uint32_t sad;
uint16_t len;
- int im, wd, area;
+ int im, wd;
int y = 0, tsy = 0, bsy = 0;
- bool mixed = ((m_mode & UPD7220_MODE_DISPLAY_MASK) == UPD7220_MODE_DISPLAY_MIXED);
- uint8_t interlace = ((m_mode & UPD7220_MODE_INTERLACE_MASK) == UPD7220_MODE_INTERLACE_ON) ? 0 : 1;
+ int mixed = ((m_mode & UPD7220_MODE_DISPLAY_MASK) == UPD7220_MODE_DISPLAY_MIXED) ? 1 : 0;
+ uint8_t interlace = ((m_mode & UPD7220_MODE_INTERLACE_MASK) == UPD7220_MODE_INTERLACE_ON) ? 1 : 0;
+ uint8_t zoom = m_disp + 1;
+
+ LOGAREA("FRAME=%d MODE=%02x FORCE BITMAP=%d ZOOM=%02x PITCH=%d\n", screen().frame_number(), m_mode, force_bitmap, zoom, m_pitch);
- for (area = 0; area < 4; area++)
+ for(int area = 0; area < 4; area++)
{
get_graphics_partition(area, &sad, &len, &im, &wd);
- if (im || force_bitmap)
- {
- //get_graphics_partition(area, &sad, &len, &im, &wd);
+ LOGAREA("%s: AREA=%d BSY=%4d SAD=%06x len=%04x im=%d wd=%d\n", this->tag(), area, bsy, sad, len, im, wd);
+
+ // pc9821:aitd (256 color mode) and pc9821:os2warp3 (16, installation screens) wants this shift
+ const u8 pitch_shift = force_bitmap ? im : mixed;
- if(area >= 3) // TODO: most likely to be correct, Quarth (PC-98xx) definitely draws with area 2. We might see an area 3 someday ...
+ if(im || force_bitmap)
+ {
+ // according to documentation only areas 0-1-2 can be drawn in bitmap mode
+ // - pc98:quarth definitely needs area 2 for player section.
+ // - pc98:steamhea wants area 3 for scrolling and dialogue screens to work together,
+ // contradicting the doc. Fixed in 7220A or applies just for mixed mode?
+ // TODO: what happens if combined area size is smaller than display height?
+ // documentation suggests that it should repeat from area 0, needs real HW verification (no known SW do it).
+ if (area >= 3 && !force_bitmap)
break;
- if(!interlace)
+ // pc98:madoum1-3 sets up ALL areas to a length of 0 after initial intro screen.
+ // madoum1: area 0 sad==0 on gameplay (PC=0x955e7), sad==0xaa0 on second intro screen (tower) then intentionally scrolls up and back to initial position.
+ // Suggests that length should be treated as max size if this occurs, this is also proven to be correct via real HW verification.
+ // TODO: check if text partition do the same.
+ if (len == 0)
+ len = 0x400;
+
+ if (interlace)
len <<= 1;
- for (y = 0; y < len; y++)
+ for(y = 0; y < len; y++)
{
- /* TODO: again correct?
- Quarth (PC-98xx) doesn't seem to use pitch here and it definitely wants bsy to be /2 to make scrolling to work.
- Xevious (PC-98xx) wants the pitch to be fixed at 80, and wants bsy to be /1
- Dragon Buster (PC-98xx) contradicts with Xevious with regards of the pitch tho ... */
- addr = ((sad << 1) & 0x3ffff) + ((y / (mixed ? 1 : m_lr)) * (m_pitch << (im ? 0 : 1)));
-
- if (!m_display_cb.isnull())
- draw_graphics_line(bitmap, addr, y + bsy + m_vbp, wd, (m_pitch << interlace));
+ // TODO: not completely correct, all is drawn half size with real HW tests on pc98 msdos by just changing PRAM values.
+ // pc98 quarth doesn't seem to use pitch here and it definitely wants bsy to be /2 to make scrolling to work.
+ // pc98 xevious wants the pitch to be fixed at 80, and wants bsy to be /1
+ // pc98 dbuster contradicts with Xevious with regards of the pitch tho ...
+ uint32_t const addr = (sad & 0x3ffff) + ((y / (mixed ? 1 : m_lr)) * (m_pitch >> pitch_shift));
+ for(int z = 0; z <= m_disp; ++z)
+ {
+ int yval = (y*zoom)+z + (bsy + m_vbp);
+ // pc9801:duel sets up bitmap layer with height 384 vs. 400 of text layer
+ // so we scissor here, interlace wants it bumped x2 (microbx2)
+ if(yval >= cliprect.top() && yval <= cliprect.bottom() && (yval - m_vbp) < m_al << interlace)
+ draw_graphics_line(bitmap, addr, yval, wd, pitch_shift);
+ }
}
}
else
{
- get_text_partition(area, &sad, &len, &im, &wd);
-
if(m_lr)
{
- for (y = 0; y < len; y+=m_lr)
+ for(y = 0; y < len; y += m_lr)
{
- addr = (sad & 0x3ffff) + ((y / m_lr) * m_pitch);
-
- if (!m_draw_text_cb.isnull())
- m_draw_text_cb(bitmap, addr, y + tsy + m_vbp, wd, m_pitch, m_lr, m_dc, m_ead);
+ uint32_t const addr = (sad & 0x3ffff) + ((y / m_lr) * m_pitch);
+ int yval = y * zoom + (tsy + m_vbp);
+ m_draw_text_cb(bitmap, addr, yval, wd, m_pitch, m_lr, m_dc, m_ead, m_ctop, m_cbot);
}
}
}
if (m_lr)
- tsy += y;
- bsy += y;
+ tsy += y * zoom;
+ bsy += y * zoom;
}
}
@@ -1687,7 +1943,7 @@ uint32_t upd7220_device::screen_update(screen_device &screen, bitmap_rgb32 &bitm
break;
case UPD7220_MODE_DISPLAY_INVALID:
- LOG("uPD7220 Invalid Display Mode!\n");
+ popmessage("%s Invalid Display Mode!", this->tag());
}
}
return 0;