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.cpp832
1 files changed, 474 insertions, 358 deletions
diff --git a/src/devices/video/upd7220.cpp b/src/devices/video/upd7220.cpp
index d1b8a95e264..ab135fd5a29 100644
--- a/src/devices/video/upd7220.cpp
+++ b/src/devices/video/upd7220.cpp
@@ -1,8 +1,9 @@
// 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
+ also known as NEC uPD7220
**********************************************************************/
@@ -11,9 +12,6 @@
TODO:
- implement FIFO as ring buffer
- - commands
- - DMAR
- - DMAW
- incomplete / unimplemented FIGD / GCHRD draw modes
- FIGD character
- slanted character
@@ -21,17 +19,15 @@
- 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;
+ Can be fixed with a DRDY mechanism for RDAT/WDAT;
+ - Some later SWs on PC-98 throws "Invalid command byte 05" (zettmj on Epson logo),
+ actual undocumented command to reset something or perhaps just check if upd7220 isn't really a upd72120 instead?
- 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"
@@ -192,25 +188,6 @@ const tiny_rom_entry *upd7220_device::device_rom_region() const
// 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);
@@ -445,18 +422,28 @@ 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 = 0xffff;
}
//-------------------------------------------------
// 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] * m_pitch);
+ m_ead &= 0x3ffff;
+
+ return data;
+}
-inline void upd7220_device::read_vram(uint8_t type, uint8_t mod)
+inline void upd7220_device::rdat(uint8_t type, uint8_t mod)
{
if (type == 1)
{
@@ -469,47 +456,82 @@ inline void upd7220_device::read_vram(uint8_t type, uint8_t 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);
+ queue(data & 0xff, 0);
+ queue((data >> 8) & 0xff, 0);
break;
case 2:
- queue(readbyte(m_ead*2), 0);
+ queue(data & 0xff, 0);
break;
case 3:
- queue(readbyte(m_ead*2+1), 0);
+ 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
+ if(type == 0)
+ current = (current & (~mask)) | (data & mask);
+ if(type == 2)
+ current = (current & ~(mask & 0xff)) | (data & (mask & 0xff));
+ if(type == 3)
+ current = (current & ~(mask & 0xff00)) | (data & (mask & 0xff00));
+ break;
+ case 0x01: //complement
+ if(type == 0)
+ current = current ^ (data & mask);
+ if(type == 2)
+ current = current ^ (data & (mask & 0xff));
+ if(type == 3)
+ current = current ^ (data & (mask & 0xff00));
+ break;
+ case 0x02: //reset to zero
+ if(type == 0)
+ current = current & ~(data & mask);
+ if(type == 2)
+ current = current & ~(data & (mask & 0xff));
+ if(type == 3)
+ current = current & ~(data & (mask & 0xff00));
+ break;
+ case 0x03: //set to one
+ if(type == 0)
+ current = current | (data & mask);
+ if(type == 2)
+ current = current | (data & (mask & 0xff));
+ if(type == 3)
+ current = current | (data & (mask & 0xff00));
+ 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)
{
@@ -534,42 +556,7 @@ 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;
- }
-
+ write_vram(type, mod, result);
m_ead += x_dir[m_figs.m_dir] + (y_dir[m_figs.m_dir] * m_pitch);
m_ead &= 0x3ffff;
}
@@ -621,10 +608,10 @@ upd7220_device::upd7220_device(const machine_config &mconfig, const char *tag, d
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),
@@ -652,7 +639,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++)
{
@@ -678,18 +665,13 @@ upd7220_device::upd7220_device(const machine_config &mconfig, const char *tag, d
void upd7220_device::device_start()
{
// resolve callbacks
- m_display_cb.resolve();
- m_draw_text_cb.resolve();
-
- 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));
@@ -712,10 +694,10 @@ 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));
@@ -749,58 +731,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);
}
@@ -808,26 +787,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;
+ LOG("uPD7220 dot check: %08x %04x %02x %02x %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);
}
}
@@ -836,219 +804,240 @@ 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);
+ LOG("uPD7220 line check: %08x %04x %02x %02x %d %d %d %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;
- 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);
+ const uint16_t octant = m_figs.m_dir;
- for(int yi = 0; yi <= m_figs.m_dc; yi++)
+ LOG("uPD7220 arc check: %08x %04x %02x %02x %d %d %d %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 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);
-
- LOG("uPD7220 rectangle check: %d %d %02x %08x\n",x,y,m_figs.m_dir,m_ead);
+ assert(m_figs.m_dc == 3);
- rect_type = (m_figs.m_dir & 1) << 2;
- rect_dir = rect_type | (((m_figs.m_dir >> 1) + 0) & 3);
+ LOG("uPD7220 rectangle check: %08x %04x %02x %02x %d %d %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);
- 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++)
- {
- draw_pixel(x,y,i,pattern);
- x+=rect_x_dir[rect_dir];
- y+=rect_y_dir[rect_dir];
- }
- rect_dir = rect_type | (((m_figs.m_dir >> 1) + 3) & 3);
+ LOG("uPD7220 char check: %08x %04x %02x %02x %d %d %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(i = 0;i < m_figs.m_d2;i++)
+ 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);
+ }
}
+}
+
+
+//-------------------------------------------------
+// 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++)
- {
- int ii = 0, curpixel = 0;
- if(pi & 1)
+ 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)
{
- ii = isize - 1;
- curpixel = (isize * (m_gchr + 1)) - 1;
+ m_ead += 1;
}
- while(pi & 1 ? ii >= 0 : ii < isize)
+ m_mask = rotate_left(m_mask);
+ break;
+ case 2:
+ if (m_mask & 0x8000)
{
- 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++;
+ m_ead += 1;
}
- if(m_figs.m_figure_type == 2)
+ m_mask = rotate_left(m_mask);
+ break;
+ case 3:
+ m_ead -= get_pitch();
+ if (m_mask & 0x8000)
{
- x += x_dir[(m_figs.m_dir + 2) & 7];
- y += y_dir[(m_figs.m_dir + 2) & 7];
+ m_ead += 1;
}
- else
+ m_mask = rotate_left(m_mask);
+ break;
+ case 4:
+ m_ead -= get_pitch();
+ break;
+ case 5:
+ m_ead -= get_pitch();
+ if (m_mask & 0x1)
{
- x += x_dir[(m_figs.m_dir + 1) & 7];
- y += y_dir[(m_figs.m_dir + 1) & 7];
+ 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;
}
@@ -1110,7 +1099,6 @@ 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);
@@ -1152,7 +1140,6 @@ void upd7220_device::process_fifo()
m_ra[0] = m_ra[1] = m_ra[2] = 0;
m_ra[3] = 0x19;
m_ead = 0;
- m_dad = 0;
m_mask = 0;
break;
@@ -1186,6 +1173,11 @@ void upd7220_device::process_fifo()
break;
case COMMAND_SYNC: /* sync format specify */
+ if (flag == FIFO_COMMAND)
+ {
+ m_de = m_cr & 1;
+ }
+
if (m_param_ptr == 9)
{
m_mode = m_pr[1];
@@ -1291,8 +1283,8 @@ void upd7220_device::process_fifo()
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);
+ LOG("uPD7220 MASK: %04x\n", m_mask);
}
}
break;
@@ -1308,6 +1300,10 @@ void upd7220_device::process_fifo()
{
LOG("uPD7220 RA%u: %02x\n", m_ra_addr, data);
+ if (m_ra_addr == 8)
+ m_pattern = (m_pattern & 0xff00) | data;
+ else if (m_ra_addr == 9)
+ m_pattern = (m_pattern & 0xff) | (data << 8);
m_ra[m_ra_addr] = data;
m_ra_addr++;
}
@@ -1330,10 +1326,16 @@ void upd7220_device::process_fifo()
if (m_param_ptr == 3 || (m_param_ptr == 2 && m_cr & 0x10))
{
+ m_pattern = (m_pattern & 0xff00) | m_pr[1];
+ if (m_param_ptr == 3)
+ m_pattern = (m_pattern & 0xff) | (m_pr[2] << 8);
+ LOG("uPD7220 PATTERN: %04x\n", m_pattern);
+ if (m_figs.m_figure_type)
+ break;
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);
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;
}
@@ -1354,6 +1356,8 @@ void upd7220_device::process_fifo()
m_figs.m_dir = m_pr[1] & 0x7;
m_figs.m_figure_type = (m_pr[1] & 0xf8) >> 3;
+ LOG("uPD7220 DIR: %02x\n", m_figs.m_dir);
+ LOG("uPD7220 FIG: %02x\n", m_figs.m_figure_type);
//if(m_figs.m_dir != 2)
// printf("DIR %02x\n",m_pr[1]);
}
@@ -1361,37 +1365,54 @@ void upd7220_device::process_fifo()
// 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)
+ {
m_figs.m_dc = (m_pr[2]) | (m_figs.m_dc & 0x3f00);
+ LOG("uPD7220 DC: %04x\n", m_figs.m_dc);
+ }
if (m_param_ptr == 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);
+ LOG("uPD7220 DC: %04x\n", m_figs.m_dc);
+ LOG("uPD7220 GD: %02x\n", m_figs.m_gd);
}
if (m_param_ptr == 6)
+ {
m_figs.m_d = (m_pr[4]) | ((m_pr[5] & 0x3f) << 8);
+ LOG("uPD7220 D: %04x\n", m_figs.m_d);
+ }
if (m_param_ptr == 8)
+ {
m_figs.m_d2 = (m_pr[6]) | ((m_pr[7] & 0x3f) << 8);
+ LOG("uPD7220 D2: %04x\n", m_figs.m_d2);
+ }
if (m_param_ptr == 10)
+ {
m_figs.m_d1 = (m_pr[8]) | ((m_pr[9] & 0x3f) << 8);
+ LOG("uPD7220 D1: %04x\n", m_figs.m_d1);
+ }
if (m_param_ptr == 12)
+ {
m_figs.m_dm = (m_pr[10]) | ((m_pr[11] & 0x3f) << 8);
+ LOG("uPD7220 DM: %04x\n", m_figs.m_dm);
+ }
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));
+ draw_pixel();
else if(m_figs.m_figure_type == 1)
- draw_line(((m_ead % eff_pitch) << 4) | (m_dad & 0xf),(m_ead / eff_pitch));
+ draw_line();
else if(m_figs.m_figure_type == 4)
- draw_arc(((m_ead % eff_pitch) << 4) | (m_dad & 0xf),(m_ead / eff_pitch));
+ draw_arc();
else if(m_figs.m_figure_type == 8)
- draw_rectangle(((m_ead % eff_pitch) << 4) | (m_dad & 0xf),(m_ead / eff_pitch));
+ draw_rectangle();
else
logerror("uPD7220 Unimplemented command FIGD %02x\n", m_figs.m_figure_type);
@@ -1401,7 +1422,7 @@ void upd7220_device::process_fifo()
case COMMAND_GCHRD: /* graphics character draw and area filling start */
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);
@@ -1412,21 +1433,20 @@ void upd7220_device::process_fifo()
case COMMAND_RDAT: /* read data from display memory */
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;
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;
@@ -1444,11 +1464,17 @@ void upd7220_device::process_fifo()
break;
case COMMAND_DMAR: /* DMA read request */
- logerror("uPD7220 Unimplemented command DMAR\n");
+ 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");
+ 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;
}
}
@@ -1463,7 +1489,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;
}
}
@@ -1493,7 +1519,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;
@@ -1529,7 +1554,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;
}
@@ -1539,6 +1593,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] * m_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] * m_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] * m_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();
+ }
}
@@ -1546,7 +1653,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);
@@ -1565,7 +1672,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 */
@@ -1587,21 +1694,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);
}
sy = y + 1;
@@ -1613,16 +1719,16 @@ 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)
+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;
+ m_display_cb(bitmap, y, sx << 4, addr + (wd + 1) * (sx % pitch));
}
}
@@ -1633,58 +1739,68 @@ 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);
+ 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) ? 0 : 1;
+ uint8_t zoom = m_disp + 1;
- 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)
+ if(im || force_bitmap)
{
- //get_graphics_partition(area, &sad, &len, &im, &wd);
-
- if(area >= 3) // TODO: most likely to be correct, Quarth (PC-98xx) definitely draws with area 2. We might see an area 3 someday ...
+ // according to documentation only areas 0-1-2 can be drawn in bitmap mode
+ // PC98 Quarth definitely needs area 2 for player section.
+ // 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)
break;
+ // 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 >> mixed));
+ for(int z = 0; z <= m_disp; ++z)
+ {
+ int yval = (y*zoom)+z + (bsy + m_vbp);
+ if(yval <= cliprect.bottom())
+ draw_graphics_line(bitmap, addr, yval, wd, mixed);
+ }
}
}
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);
}
}
}
if (m_lr)
- tsy += y;
- bsy += y;
+ tsy += y * zoom;
+ bsy += y * zoom;
}
}