nec/pc88va.cpp: implement GVRAM single/multiplane ROP registers

This commit is contained in:
angelosa 2025-03-04 21:12:55 +01:00
parent c6897b843d
commit c4092afdfa
4 changed files with 424 additions and 89 deletions

View File

@ -82,7 +82,7 @@ Operating Systems
-->
<!-- Demos and Utilities -->
<!-- !Demos -->
<!-- These three demos all have the same sequences, mislabeled? -->
<software name="pc88vad" cloneof="88va2d" supported="no">
@ -140,6 +140,8 @@ Transition between 3rd and 4th sequences don't look right, [IDP]
</part>
</software>
<!-- !Applications -->
<software name="animefrm" supported="no">
<!-- PS88-VA101-HMW subtitle on cover -->
<description>Anime Framer (v1.0)</description>
@ -204,6 +206,8 @@ Has unsupported MIF-201 [MIDI] interface cfr. http://www.pc88.gr.jp/vafaq/view.p
</part>
</software>
<!-- !Operating Systems -->
<software name="pceva2tb" supported="no">
<description>PC-Engine (VA2 Tenpu-ban)</description>
<year>1988</year>
@ -239,7 +243,7 @@ Untested directory NEC_SAMP (cannot type [keyboard] underscore char)
</software>
<!-- Games -->
<!-- !Games -->
<software name="famista" supported="no">
<description>Family Stadium</description>
@ -345,7 +349,7 @@ Winning newspaper screen has [OFX/OFY] bug
<year>198?</year>
<publisher>スタークラフト (Starcraft)</publisher>
<notes><![CDATA[
Main menu clearing artifacts [ROP]
Currently conceals/wipes out [GVRAM] display
]]></notes>
<info name="alt_title" value="マイトアンドマジック" />
<info name="usage" value="Boot with Disk C in drive 1"/>
@ -520,6 +524,7 @@ Needs graphic [OFX/OFY] scroll
<year>198?</year>
<publisher>スタークラフト (Starcraft)</publisher>
<notes><![CDATA[
Currently conceals/wipes out [GVRAM] display
Burps on [FDC] access after disk swap with program and player disks, trying to scan chrn=(38, 0, 1, 256)
]]></notes>
<info name="alt_title" value="ローグアライアンス" />
@ -876,18 +881,21 @@ Optionally wants kana lock enabled for entering a name for new game [keyboard] i
<!-- status: baddump for non-factory save 1 -->
<part name="flop1" interface="floppy_5_25">
<feature name="part_id" value="Disk 1" />
<dataarea name="flop" size="1281968">
<rom name="xak 2 (disk 1).d88" size="1281968" crc="cd855b7a" sha1="508e25ca306631be64e69e476d49116e7ac04bce" />
</dataarea>
</part>
<part name="flop2" interface="floppy_5_25">
<feature name="part_id" value="Disk 2" />
<dataarea name="flop" size="1281968">
<rom name="xak 2 (disk 2).d88" size="1281968" crc="3927cdcf" sha1="555daba18a61ea2219b5685a850b512dea085cf2" status="baddump"/>
</dataarea>
</part>
<part name="flop3" interface="floppy_5_25">
<feature name="part_id" value="Disk 3" />
<dataarea name="flop" size="1281968">
<rom name="xak 2 (disk 3).d88" size="1281968" crc="42e25779" sha1="897b62c7fdb604f5bb729e0aeb183566e08c4e33" status="baddump"/>
</dataarea>
@ -899,7 +907,7 @@ Optionally wants kana lock enabled for entering a name for new game [keyboard] i
<year>1991</year>
<publisher>マイクロキャビン (Micro Cabin)</publisher>
<notes><![CDATA[
Heavy [ROP] artifacts on intro
Heavy [ROP] artifacts on intro, runs incredibly slow
Sprites don't draw properly during gameplay [ROP]
Ugly pitch for [OPNA] voice samples on intro
[gfx]s have halved height
@ -909,24 +917,28 @@ Ugly pitch for [OPNA] voice samples on intro
<info name="usage" value="Boot with disk 2 in drive A: for gameplay"/>
<part name="flop1" interface="floppy_5_25">
<feature name="part_id" value="Disk 1" />
<dataarea name="flop" size="1261568">
<rom name="fray - in magical adventure (disk 1).fdi" size="1261568" crc="3a88990a" sha1="252e2589bb8c12800cdd678508b0abd868d0ab83"/>
</dataarea>
</part>
<part name="flop2" interface="floppy_5_25">
<feature name="part_id" value="Disk 2" />
<dataarea name="flop" size="1261568">
<rom name="fray - in magical adventure (disk 2).fdi" size="1261568" crc="9cbfb7b4" sha1="b040e4ed4e3e516effb1f6997b0f766f4b376ab4"/>
</dataarea>
</part>
<part name="flop3" interface="floppy_5_25">
<feature name="part_id" value="Disk 3" />
<dataarea name="flop" size="1261568">
<rom name="fray - in magical adventure (disk 3).fdi" size="1261568" crc="9f79f4bb" sha1="2d3ebbaa844bd451190d899a7f53829b07b830eb"/>
</dataarea>
</part>
<part name="flop4" interface="floppy_5_25">
<feature name="part_id" value="Disk 4" />
<dataarea name="flop" size="1261568">
<rom name="fray - in magical adventure (disk 4).fdi" size="1261568" crc="c074800a" sha1="bf114221bdcc8e6545c4566ae58cea1af324aa9a"/>
</dataarea>
@ -1229,7 +1241,7 @@ All disks fail initial bootstrap [FDC]
</software>
<!-- Doujin -->
<!-- !Doujinshi -->
<software name="ballbrkr" supported="no">
<description>Balloon Breaker</description>
@ -1334,7 +1346,7 @@ Gameplay don't mask bullets on right side, [cliprect]
[SGP] and [ROP] issues on gameplay
]]></notes>
<info name="developer" value="Shinra" />
<info name="usage" value="Boot a PC Engine OS disk, then swap with this disk and type BASIC PACMAN.BAS to load" />
<info name="usage" value="Boot a PC-Engine OS disk, then swap with this disk and type BASIC PACMAN.BAS to load" />
<part name="flop1" interface="floppy_5_25">
<dataarea name="flop" size="1331888">
<rom name="pacman.d88" size="1331888" crc="9198eae1" sha1="2abf462b72c29e2ff56ea7c1401836f01b97dfe1"/>
@ -1342,7 +1354,7 @@ Gameplay don't mask bullets on right side, [cliprect]
</part>
</software>
<!-- autobootable version of above, with PC Engine OS embedded -->
<!-- autobootable version of above, with PC-Engine OS embedded -->
<software name="pacmana" cloneof="pacman" supported="no">
<description>Pac-Man (auto-bootable)</description>
<year>19??</year>

View File

@ -91,14 +91,16 @@ brk 8Ch AH=02h read calendar clock -> CH = hour, CL = minutes, DH = seconds, DL
#define LOG_FDC (1U << 2) // $1b0-$1b2 accesses
#define LOG_FDC2 (1U << 3) // $1b4-$1b6 accesses (verbose)
#define LOG_GFXCTRL (1U << 4) // $5xx accesses
#define VERBOSE (LOG_GENERAL | LOG_FDC)
#define VERBOSE (LOG_GENERAL | LOG_FDC | LOG_GFXCTRL)
//#define LOG_OUTPUT_STREAM std::cout
#include "logmacro.h"
#define LOGFDC(...) LOGMASKED(LOG_FDC, __VA_ARGS__)
#define LOGFDC2(...) LOGMASKED(LOG_FDC2, __VA_ARGS__)
#define LOGGFXCTRL(...) LOGMASKED(LOG_GFXCTRL, __VA_ARGS__)
// TODO: verify clocks
#define MASTER_CLOCK XTAL(8'000'000) // may be XTAL(31'948'800) / 4? (based on PC-8801 and PC-9801)
@ -108,13 +110,13 @@ brk 8Ch AH=02h read calendar clock -> CH = hour, CL = minutes, DH = seconds, DL
uint8_t pc88va_state::kanji_ram_r(offs_t offset)
{
return m_kanjiram[offset];
return m_kanji_ram[offset];
}
// TODO: settings area should be write protected depending on the m_backupram_wp bit, separate from this
void pc88va_state::kanji_ram_w(offs_t offset, uint8_t data)
{
m_kanjiram[offset] = data;
m_kanji_ram[offset] = data;
m_gfxdecode->gfx(2)->mark_dirty(offset / 8);
m_gfxdecode->gfx(3)->mark_dirty(offset / 32);
}
@ -185,6 +187,7 @@ void pc88va_state::rtc_w(offs_t offset, u8 data)
void pc88va_state::bios_bank_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
COMBINE_DATA(&m_bank_reg);
m_gmsp_view.select(BIT(m_bank_reg, 12));
/* SMBC */
m_sysbank->set_bank((m_bank_reg & 0xf00) >> 8);
@ -510,9 +513,9 @@ TIMER_CALLBACK_MEMBER(pc88va_state::t3_mouse_callback)
uint8_t pc88va_state::backupram_dsw_r(offs_t offset)
{
if(offset == 0)
return m_kanjiram[0x1fc2 / 2] & 0xff;
return m_kanji_ram[0x1fc2 / 2] & 0xff;
return m_kanjiram[0x1fc6 / 2] & 0xff;
return m_kanji_ram[0x1fc6 / 2] & 0xff;
}
// TODO: pc8801_state::port31_w
@ -552,13 +555,15 @@ void pc88va_state::main_map(address_map &map)
void pc88va_state::sysbank_map(address_map &map)
{
// 0 select bus slot
// 0 select C-bus slot
// 1 tvram
map(0x040000, 0x04ffff).ram().share("tvram");
// FIXME: BASIC and pacmana expects to r/w to 0x60000-0x7ffff on loading, assume mirror if not a core bug.
map(0x050000, 0x07ffff).ram();
// 4 gvram
map(0x100000, 0x13ffff).ram().share("gvram");
map(0x100000, 0x13ffff).view(m_gmsp_view);
m_gmsp_view[0](0x100000, 0x13ffff).rw(FUNC(pc88va_state::gvram_multiplane_r), FUNC(pc88va_state::gvram_multiplane_w));
m_gmsp_view[1](0x100000, 0x13ffff).rw(FUNC(pc88va_state::gvram_singleplane_r), FUNC(pc88va_state::gvram_singleplane_w));
// 8-9 kanji
// Kanji ROM
map(0x200000, 0x23ffff).rom().region("kanji", 0x00000);
@ -580,7 +585,11 @@ void pc88va_state::sgp_map(address_map &map)
map(0x140000, 0x14ffff).rom().region("kanji", 0x40000);
map(0x150000, 0x153fff).rw(FUNC(pc88va_state::kanji_ram_r),FUNC(pc88va_state::kanji_ram_w));
map(0x180000, 0x18ffff).ram().share("tvram");
map(0x200000, 0x23ffff).ram().share("gvram");
// Assume just raw writes to GVRAM
map(0x200000, 0x23ffff).lrw8(
NAME([this] (offs_t offset) { return m_gvram[offset]; }),
NAME([this] (offs_t offset, u8 data) { m_gvram[offset] = data; })
);
}
// TODO: I/O 0x00xx is almost same as pc8801
@ -661,22 +670,155 @@ void pc88va_state::io_map(address_map &map)
map(0x0500, 0x0507).m(m_sgp, FUNC(pc88va_sgp_device::sgp_io));
// GVRAM multiplane access regs (ROP section)
// map(0x0510, 0x0510) AACC extend access mode
// map(0x0512, 0x0512) GMAP block switch
// map(0x0514, 0x0514) XRPMn plane readback select
// map(0x0516, 0x0516) XWPMn plane write select
// map(0x0518, 0x0518) multiplane enable
// map(0x0520, 0x0527).umask16(0x00ff) extended access bit comparison
// TODO: register are locked with GMSP = 1
map(0x0510, 0x0510).lrw8(
NAME([this] (offs_t offset) {
LOGGFXCTRL("AACC extend access mode R\n");
return m_multiplane.aacc;
}),
NAME([this] (offs_t offset, u8 data) {
m_multiplane.aacc = !!BIT(data, 0);
LOGGFXCTRL("AACC extend access mode W %02x\n", data);
})
);
map(0x0512, 0x0512).lrw8(
NAME([this] (offs_t offset) {
LOGGFXCTRL("GMAP block switch R\n");
return m_multiplane.gmap;
}),
NAME([this] (offs_t offset, u8 data) {
LOGGFXCTRL("GMAP block switch W %02x\n", data);
m_multiplane.gmap = !!BIT(data, 0);
})
);
map(0x0514, 0x0514).lrw8(
NAME([this] (offs_t offset) {
LOGGFXCTRL("XRPMn plane readback select R\n");
return m_multiplane.xrpm | 0xf0;
}),
NAME([this] (offs_t offset, u8 data) {
LOGGFXCTRL("XRPMn plane readback select W %02x\n", data);
m_multiplane.xrpm = data & 0xf;
})
);
map(0x0516, 0x0516).lrw8(
NAME([this] (offs_t offset) {
LOGGFXCTRL("XWPMn plane write select R\n");
return m_multiplane.xwpm | 0xf0;
}),
NAME([this] (offs_t offset, u8 data) {
LOGGFXCTRL("XWPMn plane write select W %02x\n", data);
m_multiplane.xwpm = data & 0xf;
})
);
map(0x0518, 0x0518).lrw8(
NAME([this] (offs_t offset) {
// TODO: rbusy reads (bit 7)
return (m_multiplane.cmpen << 5) | (m_multiplane.wss << 3) | (m_multiplane.pmod << 0);
}),
NAME([this] (offs_t offset, u8 data) {
LOGGFXCTRL("Multiplane Mode W %02x\n", data);
// PMOD bit 2 1 -> 0 transitions resets pattern pointers
if (BIT(m_multiplane.pmod, 2) && !BIT(data, 2))
{
m_multiplane.prrp = 0;
m_multiplane.prwp = 0;
}
m_multiplane.cmpen = !!BIT(data, 5);
m_multiplane.wss = (data >> 3) & 3;
m_multiplane.pmod = (data >> 0) & 7;
})
);
map(0x0520, 0x0527).umask16(0x00ff).lrw8(
NAME([this] (offs_t offset) {
LOGGFXCTRL("CMPR extended access bit comparison R\n");
return m_multiplane.cmpr[offset];
}),
NAME([this] (offs_t offset, u8 data) {
LOGGFXCTRL("CMPR extended access bit comparison W %02x\n", data);
m_multiplane.cmpr[offset] = data;
})
);
// map(0x0528, 0x0528) extended access plane comparison
// map(0x0530, 0x0537).umask16(0x00ff) extended access pattern low byte
// map(0x0540, 0x0547).umask16(0x00ff) extended access pattern high byte
// map(0x0550, 0x0550) PRRPn plane pattern usage start byte on read
// map(0x0552, 0x0552) PRWPn plane pattern usage start byte on write
// map(0x0560, 0x0567).umask16(0x00ff) ROP plane code
map(0x0530, 0x0537).umask16(0x00ff).lrw8(
NAME([this] (offs_t offset) {
LOGGFXCTRL("Multiplane PATRL%d R\n", offset);
return m_multiplane.patr[offset][0];
}),
NAME([this] (offs_t offset, u8 data) {
LOGGFXCTRL("Multiplane PATRL%d W %02x\n", offset, data);
m_multiplane.patr[offset][0] = data;
})
);
map(0x0540, 0x0547).umask16(0x00ff).lrw8(
NAME([this] (offs_t offset) {
LOGGFXCTRL("PATRH%d R\n", offset);
return m_multiplane.patr[offset][1];
}),
NAME([this] (offs_t offset, u8 data) {
LOGGFXCTRL("PATRH%d W %02x\n", offset, data);
m_multiplane.patr[offset][1] = data;
})
);
map(0x0550, 0x0550).umask16(0x00ff).lrw8(
NAME([this] (offs_t offset) {
return m_multiplane.prrp | 0xf0;
}),
NAME([this] (offs_t offset, u8 data) {
LOGGFXCTRL("PRRPn plane pattern usage start byte on read %02x\n", data);
m_multiplane.prrp = data & 0xf;
})
);
map(0x0552, 0x0552).umask16(0x00ff).lrw8(
NAME([this] (offs_t offset) {
return m_multiplane.prwp | 0xf0;
}),
NAME([this] (offs_t offset, u8 data) {
LOGGFXCTRL("PRWPn plane pattern usage start byte on write %02x\n", data);
m_multiplane.prwp = data & 0xf;
})
);
map(0x0560, 0x0567).umask16(0x00ff).lrw8(
NAME([this] (offs_t offset) {
return m_multiplane.rop[offset];
}),
NAME([this] (offs_t offset, u8 data) {
LOGGFXCTRL("Multiplane ROP %d W %02x\n", offset, data);
m_multiplane.rop[offset] = data;
})
);
// GVRAM single plane access regs
// map(0x0580, 0x0580) single plane enable
// map(0x0590, 0x0593) GVRAM pattern register settings
// map(0x05a0, 0x05a3) ROP plane code
// TODO: register are locked with GMSP = 0
map(0x0580, 0x0580).lrw8(
NAME([this] (offs_t offset) {
// TODO: rbusy reads (bit 7)
return (m_singleplane.wss << 3);
}),
NAME([this] (offs_t offset, u8 data) {
LOGGFXCTRL("Singleplane Mode W %02x\n", data);
m_singleplane.wss = (data >> 3) & 3;
})
);
map(0x0590, 0x0593).umask16(0x00ff).lrw8(
NAME([this] (offs_t offset) {
LOGGFXCTRL("Singleplane PATRL%d R\n", offset);
return m_singleplane.patr[offset];
}),
NAME([this] (offs_t offset, u8 data) {
LOGGFXCTRL("Singleplane PATRL%d W %02x\n", offset, data);
m_singleplane.patr[offset] = data;
})
);
map(0x05a0, 0x05a3).umask16(0x00ff).lrw8(
NAME([this] (offs_t offset) {
return m_singleplane.rop[offset];
}),
NAME([this] (offs_t offset, u8 data) {
LOGGFXCTRL("Singleplane ROP %d W %02x\n", offset, data);
m_singleplane.rop[offset] = data;
})
);
// map(0x1000, 0xfeff) PC-88VA expansion boards
// map(0xe2d2, 0xe2d2) MIDI status in micromus

View File

@ -66,10 +66,10 @@ public:
, m_sysbank(*this, "sysbank")
, m_workram(*this, "workram")
, m_tvram(*this, "tvram")
, m_gvram(*this, "gvram")
, m_fb_regs(*this, "fb_regs")
, m_kanji_rom(*this, "kanji")
, m_sgp(*this, "sgp")
, m_gmsp_view(*this, "gmsp_view")
, m_kanji_rom(*this, "kanji")
, m_gfxdecode(*this, "gfxdecode")
, m_palette(*this, "palette")
{ }
@ -107,6 +107,7 @@ protected:
virtual void machine_start() override ATTR_COLD;
virtual void machine_reset() override ATTR_COLD;
virtual void video_start() override ATTR_COLD;
virtual void video_reset() override ATTR_COLD;
void palette_init(palette_device &palette) const;
protected:
@ -131,11 +132,12 @@ private:
required_device<address_map_bank_device> m_sysbank;
required_shared_ptr<uint16_t> m_workram;
required_shared_ptr<uint16_t> m_tvram;
required_shared_ptr<uint16_t> m_gvram;
std::unique_ptr<uint8_t[]> m_gvram;
required_shared_ptr<uint16_t> m_fb_regs;
required_region_ptr<u16> m_kanji_rom;
required_device<pc88va_sgp_device> m_sgp;
std::unique_ptr<uint8_t[]> m_kanjiram;
memory_view m_gmsp_view;
required_region_ptr<u16> m_kanji_rom;
std::unique_ptr<uint8_t[]> m_kanji_ram;
uint16_t m_bank_reg = 0;
uint8_t m_timer3_io_reg = 0;
@ -191,20 +193,48 @@ private:
void r232_ctrl_portc_w(uint8_t data);
uint8_t get_slave_ack(offs_t offset);
uint16_t m_video_pri_reg[2]{};
uint16_t m_video_pri_reg[2];
u16 m_screen_ctrl_reg = 0;
bool m_dm = false;
bool m_ymmd = false;
u16 m_gfx_ctrl_reg = 0;
u16 m_screen_ctrl_reg;
bool m_dm;
bool m_ymmd;
u16 m_gfx_ctrl_reg;
u16 m_color_mode = 0;
u8 m_pltm, m_pltp = 0;
u16 m_color_mode;
u8 m_pltm, m_pltp;
u16 m_text_transpen = 0;
bool m_td = false;
u16 m_text_transpen;
bool m_td;
bitmap_rgb32 m_graphic_bitmap[2];
struct {
bool aacc;
u8 gmap;
u8 xrpm, xwpm;
//bool rbusy;
bool cmpen;
u8 wss;
u8 pmod;
u8 rop[4];
u8 cmpr[4];
u8 patr[4][2];
u8 prrp, prwp;
} m_multiplane;
struct {
//bool rbusy;
u8 wss;
u8 patr[2];
u8 rop[2];
} m_singleplane;
u8 rop_execute(u8 plane_rop, u8 src, u8 dst, u8 pat);
u8 gvram_singleplane_r(offs_t offset);
void gvram_singleplane_w(offs_t offset, u8 data);
u8 gvram_multiplane_r(offs_t offset);
void gvram_multiplane_w(offs_t offset, u8 data);
u16 screen_ctrl_r();
void screen_ctrl_w(offs_t offset, u16 data, u16 mem_mask = ~0);
u16 gfx_ctrl_r();
@ -272,11 +302,11 @@ private:
void sgp_map(address_map &map) ATTR_COLD;
// TODO: stuff backported from PC8801 as QoL that should really be common
protected:
required_device<gfxdecode_device> m_gfxdecode;
required_device<palette_device> m_palette;
// TODO: stuff backported from PC8801 as QoL that should really be common
private:
uint8_t misc_ctrl_r();
void misc_ctrl_w(uint8_t data);

View File

@ -28,10 +28,14 @@
void pc88va_state::video_start()
{
const u32 gvram_size = 0x40000;
m_gvram = std::make_unique<uint8_t[]>(gvram_size);
std::fill_n(m_gvram.get(), gvram_size, 0);
const u32 kanjiram_size = 0x4000;
m_kanjiram = std::make_unique<uint8_t[]>(kanjiram_size);
m_gfxdecode->gfx(2)->set_source(m_kanjiram.get());
m_gfxdecode->gfx(3)->set_source(m_kanjiram.get());
m_kanji_ram = std::make_unique<uint8_t[]>(kanjiram_size);
m_gfxdecode->gfx(2)->set_source(m_kanji_ram.get());
m_gfxdecode->gfx(3)->set_source(m_kanji_ram.get());
m_vrtc_irq_line = 432;
for (int i = 0; i < 2; i++)
@ -45,11 +49,17 @@ void pc88va_state::video_start()
save_item(NAME(m_text_transpen));
save_pointer(NAME(m_video_pri_reg), 2);
save_pointer(NAME(m_kanjiram), kanjiram_size);
save_pointer(NAME(m_gvram), gvram_size);
save_pointer(NAME(m_kanji_ram), kanjiram_size);
save_item(NAME(m_vrtc_irq_line));
}
void pc88va_state::video_reset()
{
m_text_transpen = 0;
}
void pc88va_state::palette_init(palette_device &palette) const
{
// default palette
@ -69,7 +79,6 @@ void pc88va_state::palette_init(palette_device &palette) const
}
}
uint32_t pc88va_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
uint8_t pri, cur_pri_lv;
@ -607,7 +616,7 @@ void pc88va_state::draw_text(bitmap_rgb32 &bitmap, const rectangle &cliprect)
if(!split_cliprect.contains(res_x, res_y))
continue;
int pen = m_kanjiram[(( yi * 2 ) + lr_half_gfx) + tile_num] >> (7 - xi) & 1;
int pen = m_kanji_ram[(( yi * 2 ) + lr_half_gfx) + tile_num] >> (7 - xi) & 1;
if(reverse)
pen = pen & 1 ? bg_col : fg_col;
@ -795,8 +804,6 @@ void pc88va_state::draw_graphic_layer(bitmap_rgb32 &bitmap, const rectangle &cli
void pc88va_state::draw_indexed_gfx_1bpp(bitmap_rgb32 &bitmap, const rectangle &cliprect, u32 fb_start_offset, u8 pal_base)
{
uint8_t *gvram = (uint8_t *)m_gvram.target();
for(int y = cliprect.min_y; y <= cliprect.max_y; y++)
{
const u32 line_offset = (((y * 640) / 8) + fb_start_offset) & 0x3ffff;
@ -808,7 +815,7 @@ void pc88va_state::draw_indexed_gfx_1bpp(bitmap_rgb32 &bitmap, const rectangle &
for (int xi = 0; xi < 8; xi ++)
{
uint32_t color = (gvram[bitmap_offset] >> (7 - xi)) & 1;
uint32_t color = (m_gvram[bitmap_offset] >> (7 - xi)) & 1;
int res_x = x + xi;
if(color && cliprect.contains(res_x, y))
@ -820,8 +827,6 @@ void pc88va_state::draw_indexed_gfx_1bpp(bitmap_rgb32 &bitmap, const rectangle &
void pc88va_state::draw_indexed_gfx_4bpp(bitmap_rgb32 &bitmap, const rectangle &cliprect, u32 fb_start_offset, u32 display_start_offset, u8 pal_base, u16 fb_width, u16 fb_height)
{
uint8_t *gvram = (uint8_t *)m_gvram.target();
// const u16 y_min = std::max(cliprect.min_y, y_start);
// const u16 y_max = std::min(cliprect.max_y, y_min + fb_height);
@ -838,7 +843,7 @@ void pc88va_state::draw_indexed_gfx_4bpp(bitmap_rgb32 &bitmap, const rectangle &
for (int xi = 0; xi < 2; xi ++)
{
u8 color = (gvram[bitmap_offset] >> (xi ? 0 : 4)) & 0xf;
u8 color = (m_gvram[bitmap_offset] >> (xi ? 0 : 4)) & 0xf;
if(color && cliprect.contains(x + xi, y))
bitmap.pix(y, x + xi) = m_palette->pen(color + pal_base);
@ -849,8 +854,6 @@ void pc88va_state::draw_indexed_gfx_4bpp(bitmap_rgb32 &bitmap, const rectangle &
void pc88va_state::draw_packed_gfx_5bpp(bitmap_rgb32 &bitmap, const rectangle &cliprect, u32 fb_start_offset, u32 display_start_offset, u8 pal_base, u16 fb_width, u16 fb_height)
{
uint8_t *gvram = (uint8_t *)m_gvram.target();
// const u16 y_min = std::max(cliprect.min_y, y_start);
// const u16 y_max = std::min(cliprect.max_y, y_min + fb_height);
@ -864,7 +867,7 @@ void pc88va_state::draw_packed_gfx_5bpp(bitmap_rgb32 &bitmap, const rectangle &c
{
u32 bitmap_offset = line_offset + x;
u8 color = gvram[bitmap_offset] & 0x1f;
u8 color = m_gvram[bitmap_offset] & 0x1f;
if(color && cliprect.contains(x, y))
bitmap.pix(y, x) = m_palette->pen(color);
@ -874,8 +877,6 @@ void pc88va_state::draw_packed_gfx_5bpp(bitmap_rgb32 &bitmap, const rectangle &c
void pc88va_state::draw_direct_gfx_8bpp(bitmap_rgb32 &bitmap, const rectangle &cliprect, u32 fb_start_offset, u16 fb_width, u16 fb_height)
{
uint8_t *gvram = (uint8_t *)m_gvram.target();
// const u16 y_min = std::max(cliprect.min_y, y_start);
// const u16 y_max = std::min(cliprect.max_y, y_min + fb_height);
@ -887,7 +888,7 @@ void pc88va_state::draw_direct_gfx_8bpp(bitmap_rgb32 &bitmap, const rectangle &c
{
u32 bitmap_offset = line_offset + x;
uint32_t color = (gvram[bitmap_offset] & 0xff);
uint32_t color = (m_gvram[bitmap_offset] & 0xff);
// boomer suggests that transparency is calculated over just color = 0, may be settable?
// TODO: may not be clamped to palNbit
@ -904,8 +905,6 @@ void pc88va_state::draw_direct_gfx_8bpp(bitmap_rgb32 &bitmap, const rectangle &c
void pc88va_state::draw_direct_gfx_rgb565(bitmap_rgb32 &bitmap, const rectangle &cliprect, u32 fb_start_offset, u16 fb_width, u16 fb_height)
{
uint8_t *gvram = (uint8_t *)m_gvram.target();
// const u16 y_min = std::max(cliprect.min_y, y_start);
// const u16 y_max = std::min(cliprect.max_y, y_min + fb_height);
@ -917,7 +916,7 @@ void pc88va_state::draw_direct_gfx_rgb565(bitmap_rgb32 &bitmap, const rectangle
{
u32 bitmap_offset = (line_offset + x) << 1;
uint16_t color = (gvram[bitmap_offset] & 0xff) | (gvram[bitmap_offset + 1] << 8);
uint16_t color = (m_gvram[bitmap_offset] & 0xff) | (m_gvram[bitmap_offset + 1] << 8);
if(cliprect.contains(x, y))
{
@ -932,8 +931,6 @@ void pc88va_state::draw_direct_gfx_rgb565(bitmap_rgb32 &bitmap, const rectangle
void pc88va_state::draw_packed_gfx_4bpp(bitmap_rgb32 &bitmap, const rectangle &cliprect, u32 fb_start_offset, u32 display_start_offset, u8 pal_base, u16 fb_width, u16 fb_height)
{
uint8_t *gvram = (uint8_t *)m_gvram.target();
// const u16 y_min = std::max(cliprect.min_y, y_start);
// const u16 y_max = std::min(cliprect.max_y, y_min + fb_height);
@ -950,7 +947,7 @@ void pc88va_state::draw_packed_gfx_4bpp(bitmap_rgb32 &bitmap, const rectangle &c
{
u8 color = 0;
for (int bank_num = 0; bank_num < 4; bank_num ++)
color |= ((gvram[bitmap_offset + bank_num * 0x10000] >> (7 - xi)) & 1) << bank_num;
color |= ((m_gvram[bitmap_offset + bank_num * 0x10000] >> (7 - xi)) & 1) << bank_num;
if(color && cliprect.contains(x + xi, y))
bitmap.pix(y, x + xi) = m_palette->pen(color + pal_base);
@ -1615,7 +1612,7 @@ u8 pc88va_state::kanji_cg_r()
// jis2 = 0x21 / 0x22 "PC" on hovered top status bar for animefrm
// NB: software reverts the two chars once it gets upped to bitmap layer.
const u32 pcg_addr = ((m_kanji_cg_jis[1] & 0x1f) + ((m_kanji_cg_jis[1] & 0x60) << 1)) * 0x20;
return m_kanjiram[pcg_addr + (m_kanji_cg_line << 1) + (m_kanji_cg_lr ^ 1)];
return m_kanji_ram[pcg_addr + (m_kanji_cg_line << 1) + (m_kanji_cg_lr ^ 1)];
}
const u32 kanji_address = calc_kanji_rom_addr(m_kanji_cg_jis[0] + 0x20, m_kanji_cg_jis[1], 0, 0);
@ -1652,3 +1649,157 @@ void pc88va_state::text_control_1_w(u8 data)
if ((data & 0x7d) != 1)
LOG("I/O $148 write %02x\n", data);
}
/****************************************
* GVRAM
***************************************/
u8 pc88va_state::rop_execute(u8 plane_rop, u8 src, u8 dst, u8 pat)
{
u8 res = 0;
for (int i = 0; i < 8; i++)
{
if (BIT(plane_rop, i))
{
u8 src_data = BIT(i, 0) ? src : ~src;
u8 dst_data = BIT(i, 1) ? dst : ~dst;
u8 pat_data = BIT(i, 2) ? pat : ~pat;
res |= src_data & dst_data & pat_data;
}
}
return res;
}
u8 pc88va_state::gvram_multiplane_r(offs_t offset)
{
if (m_multiplane.aacc)
{
u32 address = (offset & 0x7fff) | (m_multiplane.gmap << 15);
u8 res = 0xff;
for (int plane = 0; plane < 4; plane++)
{
if (!BIT(m_multiplane.xrpm, plane))
{
const u8 src = m_gvram[address | plane * 0x10000];
// Comparison enable
if (m_multiplane.cmpen)
res &= ~(src ^ m_multiplane.cmpr[plane]);
else
res &= src;
// update on reads
if (BIT(m_multiplane.pmod, 0) && !machine().side_effects_disabled())
{
m_multiplane.patr[plane][BIT(m_multiplane.prwp, plane)] = src;
}
}
}
// flip register indices on 16-bit mode
if ((m_multiplane.pmod & 5) == 5 && !machine().side_effects_disabled())
{
m_multiplane.prwp ^= 0xf;
}
return res;
}
return gvram_singleplane_r(offset);
}
void pc88va_state::gvram_multiplane_w(offs_t offset, u8 data)
{
if (m_multiplane.aacc)
{
u32 address = (offset & 0x7fff) | (m_multiplane.gmap << 15);
for (int plane = 0; plane < 4; plane++)
{
if (!BIT(m_multiplane.xwpm, plane))
{
switch(m_multiplane.wss & 3)
{
// ROP
case 0:
{
const u8 src = m_gvram[address | plane * 0x10000];
m_gvram[address | plane * 0x10000] = rop_execute(
m_multiplane.rop[plane],
src,
data,
m_multiplane.patr[plane][BIT(m_multiplane.prrp, plane)]
);
// update pattern on writes
if (BIT(m_multiplane.pmod, 1))
{
m_multiplane.patr[plane][BIT(m_multiplane.prwp, plane)] = src;
}
break;
}
// Pattern
case 1:
m_gvram[address | plane * 0x10000] = m_multiplane.patr[plane][BIT(m_multiplane.prrp, plane)];
break;
// Normal writes
case 2:
m_gvram[address | plane * 0x10000] = data;
break;
// NOP
case 3:
break;
}
}
}
// flip register indices on 16-bit mode
if (BIT(m_multiplane.pmod, 2))
{
m_multiplane.prrp ^= 0xf;
if (BIT(m_multiplane.pmod, 1))
m_multiplane.prwp ^= 0xf;
}
return;
}
gvram_singleplane_w(offset, data);
}
u8 pc88va_state::gvram_singleplane_r(offs_t offset)
{
// apparently no side effects on reads
return m_gvram[offset];
}
void pc88va_state::gvram_singleplane_w(offs_t offset, u8 data)
{
const u8 page_bank = BIT(offset, 17);
switch(m_singleplane.wss & 3)
{
// ROP
case 0:
{
const u8 src = m_gvram[offset];
m_gvram[offset] = rop_execute(
m_singleplane.rop[page_bank],
src,
data,
m_singleplane.patr[page_bank]
);
break;
}
// Pattern
case 1:
m_gvram[offset] = m_singleplane.patr[page_bank];
break;
// Normal writes
case 2:
m_gvram[offset] = data;
break;
// NOP
case 3:
break;
}
}