nintendo/vboy.cpp: convert HW and VIPS I/O to address_map, add IO_SPACE r/w, misc cleanups

* fix longstanding regressions with panicbom, galactic and vforce;
This commit is contained in:
angelosa 2023-04-08 01:46:38 +02:00
parent 406b4d53b8
commit c05772f9c6
2 changed files with 295 additions and 312 deletions

View File

@ -59,12 +59,11 @@ Runs way too fast
</part>
</software>
<software name="galactic" supported="no">
<software name="galactic" supported="partial">
<description>Galactic Pinball (Japan, USA)</description>
<year>1995</year>
<publisher>Nintendo</publisher>
<notes><![CDATA[
I/O access (regression)
Ball goes out of bounds sometimes on gameplay (verify)
]]></notes>
<info name="developer" value="Intelligent Systems"/>
@ -230,13 +229,10 @@ Gameplay [VIP] flickers too much, framebuffer?
</part>
</software>
<software name="panicbom" supported="no">
<software name="panicbom" supported="partial">
<description>Panic Bomber (USA)</description>
<year>1995</year>
<publisher>Nintendo</publisher>
<notes><![CDATA[
I/O access for sound (regression)
]]></notes>
<info name="developer" value="Raizing"/>
<info name="serial" value="VUE-VH2E-USA"/>
<info name="release" value="199512xx"/>
@ -375,13 +371,10 @@ Verify player KO graphics
</part>
</software>
<software name="tobidase" cloneof="panicbom" supported="no">
<software name="tobidase" cloneof="panicbom" supported="partial">
<description>Tobidase! Panibon (Japan)</description>
<year>1995</year>
<publisher>Hudson</publisher>
<notes><![CDATA[
I/O access for sound (regression)
]]></notes>
<info name="developer" value="Raizing"/>
<info name="serial" value="VUE-VH2J-JPN"/>
<info name="release" value="19950721"/>
@ -432,13 +425,10 @@ Missing GFXs for gender select in name entry
</part>
</software>
<software name="vforce" supported="no">
<software name="vforce" supported="partial">
<description>Vertical Force (USA)</description>
<year>1995</year>
<publisher>Nintendo</publisher>
<notes><![CDATA[
I/O access (regression)
]]></notes>
<info name="developer" value="Hudson"/>
<info name="serial" value="VUE-VH3E-USA"/>
<info name="release" value="19951201"/>
@ -449,13 +439,10 @@ I/O access (regression)
</part>
</software>
<software name="vforcej" cloneof="vforce" supported="no">
<software name="vforcej" cloneof="vforce" supported="partial">
<description>Vertical Force (Japan)</description>
<year>1995</year>
<publisher>Hudson</publisher>
<notes><![CDATA[
I/O access (regression)
]]></notes>
<info name="developer" value="Hudson"/>
<info name="serial" value="VUE-VH3J-JPN"/>
<info name="release" value="19950812"/>

View File

@ -91,7 +91,7 @@ private:
uint32_t tcr = 0, wcr = 0, kcr = 0x80;
};
struct vip_regs_t
struct vip_io_regs_t
{
uint16_t INTPND = 0;
uint16_t INTENB = 0;
@ -129,9 +129,9 @@ private:
std::unique_ptr<uint8_t[]> m_l_frame_1;
std::unique_ptr<uint8_t[]> m_r_frame_0;
std::unique_ptr<uint8_t[]> m_r_frame_1;
vboy_regs_t m_vboy_regs;
vip_regs_t m_vip_regs;
vboy_timer_t m_vboy_timer;
vboy_regs_t m_regs;
vip_io_regs_t m_vip_io;
vboy_timer_t m_timer;
std::unique_ptr<int32_t[]> m_ovr_tempdraw_map;
uint16_t m_frame_count = 0;
uint8_t m_displayfb = 0;
@ -139,10 +139,15 @@ private:
uint8_t m_row_num = 0;
attotime m_input_latch_time;
uint32_t io_r(offs_t offset);
void io_w(offs_t offset, uint32_t data);
uint16_t vip_r(offs_t offset);
void vip_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
void io_map(address_map &map);
u8 timer_control_r();
void timer_control_w(offs_t offset, u8 data);
u8 keypad_control_r();
void keypad_control_w(offs_t offset, u8 data);
void vip_map(address_map &map);
uint16_t vip_io_r(offs_t offset);
void vip_io_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
void font0_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
void font1_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
void font2_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
@ -151,8 +156,8 @@ private:
uint16_t font1_r(offs_t offset);
uint16_t font2_r(offs_t offset);
uint16_t font3_r(offs_t offset);
void vboy_bgmap_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
uint16_t vboy_bgmap_r(offs_t offset);
void bgmap_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
uint16_t bgmap_r(offs_t offset);
uint8_t lfb0_r(offs_t offset);
uint8_t lfb1_r(offs_t offset);
uint8_t rfb0_r(offs_t offset);
@ -162,9 +167,8 @@ private:
void rfb0_w(offs_t offset, uint8_t data);
void rfb1_w(offs_t offset, uint8_t data);
void m_timer_tick();
void m_scanline_tick(int scanline, uint8_t screen_type);
void m_set_irq(uint16_t irq_vector);
void scanline_tick(int scanline, uint8_t screen_type);
void set_irq(uint16_t irq_vector);
void put_obj(bitmap_ind16 &bitmap, const rectangle &cliprect, int x, int y, uint16_t code, uint8_t pal);
void fill_ovr_char(uint16_t code, uint8_t pal);
@ -174,15 +178,16 @@ private:
void draw_affine_map(bitmap_ind16 &bitmap, const rectangle &cliprect, uint16_t param_base, int gx, int gp, int gy, int h, int w,
uint16_t x_mask, uint16_t y_mask, uint8_t ovr, bool right, int bg_map_num);
uint8_t display_world(int num, bitmap_ind16 &bitmap, const rectangle &cliprect, bool right, int &cur_spt);
void m_set_brightness();
void set_brightness();
void vboy_palette(palette_device &palette) const;
uint32_t screen_update_vboy_left(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
uint32_t screen_update_vboy_right(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
uint32_t screen_update_left(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
uint32_t screen_update_right(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
TIMER_DEVICE_CALLBACK_MEMBER(timer_main_tick);
TIMER_DEVICE_CALLBACK_MEMBER(timer_pad_tick);
TIMER_DEVICE_CALLBACK_MEMBER(vboy_scanlineL);
void vboy_mem(address_map &map);
void vboy_map(address_map &map);
void vboy_io(address_map &map);
};
@ -255,7 +260,7 @@ inline int8_t vboy_state::get_bg_map_pixel(int num, int xpos, int ypos)
uint8_t const stepx = (x & 0x1c0) >> 6;
uint8_t const stepy = ((y & 0x1c0) >> 6) * (stepx+1);
uint16_t const val = READ_BGMAP((x & 0x3f) + (64 * (y & 0x3f)) + ((num + stepx + stepy) * 0x1000));
int const pal = m_vip_regs.GPLT[(val >> 14) & 3];
int const pal = m_vip_io.GPLT[(val >> 14) & 3];
int const code = val & 0x3fff;
uint8_t const yi = ypos & 7;
@ -408,7 +413,7 @@ uint8_t vboy_state::display_world(int num, bitmap_ind16 &bitmap, const rectangle
if (mode < 2) // Normal / HBias Mode
{
if(ovr)
fill_ovr_char(ovr_char & 0x3fff, m_vip_regs.GPLT[(ovr_char >> 14) & 3]);
fill_ovr_char(ovr_char & 0x3fff, m_vip_io.GPLT[(ovr_char >> 14) & 3]);
if (lon && (!right))
{
@ -423,7 +428,7 @@ uint8_t vboy_state::display_world(int num, bitmap_ind16 &bitmap, const rectangle
else if (mode==2) // Affine Mode
{
if(ovr)
fill_ovr_char(ovr_char & 0x3fff, m_vip_regs.GPLT[(ovr_char >> 14) & 3]);
fill_ovr_char(ovr_char & 0x3fff, m_vip_io.GPLT[(ovr_char >> 14) & 3]);
if (lon && (!right))
{
@ -443,11 +448,11 @@ uint8_t vboy_state::display_world(int num, bitmap_ind16 &bitmap, const rectangle
return 0;
}
int start_offs = m_vip_regs.SPT[cur_spt];
int start_offs = m_vip_io.SPT[cur_spt];
int end_offs = 0x3ff;
if(cur_spt != 0)
end_offs = m_vip_regs.SPT[cur_spt-1];
end_offs = m_vip_io.SPT[cur_spt-1];
int i = start_offs;
do
@ -461,10 +466,10 @@ uint8_t vboy_state::display_world(int num, bitmap_ind16 &bitmap, const rectangle
uint8_t jron = (READ_OBJECTS(start_ndx+1) & 0x4000) >> 14;
if (!right && jlon)
put_obj(bitmap, cliprect, (jx-jp) & 0x1ff, jy, val & 0x3fff, m_vip_regs.JPLT[(val>>14) & 3]);
put_obj(bitmap, cliprect, (jx-jp) & 0x1ff, jy, val & 0x3fff, m_vip_io.JPLT[(val>>14) & 3]);
if(right && jron)
put_obj(bitmap, cliprect, (jx+jp) & 0x1ff, jy, val & 0x3fff, m_vip_regs.JPLT[(val>>14) & 3]);
put_obj(bitmap, cliprect, (jx+jp) & 0x1ff, jy, val & 0x3fff, m_vip_io.JPLT[(val>>14) & 3]);
i--;
i &= 0x3ff;
@ -477,12 +482,12 @@ uint8_t vboy_state::display_world(int num, bitmap_ind16 &bitmap, const rectangle
return 0;
}
uint32_t vboy_state::screen_update_vboy_left(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
uint32_t vboy_state::screen_update_left(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
bitmap.fill(m_palette->pen(m_vip_regs.BKCOL), cliprect);
bitmap.fill(m_palette->pen(m_vip_io.BKCOL), cliprect);
int cur_spt;
if(!(m_vip_regs.DPCTRL & 2)) /* Don't bother if screen is off */
if(!(m_vip_io.DPCTRL & 2)) /* Don't bother if screen is off */
return 0;
cur_spt = 3;
@ -507,12 +512,12 @@ uint32_t vboy_state::screen_update_vboy_left(screen_device &screen, bitmap_ind16
return 0;
}
uint32_t vboy_state::screen_update_vboy_right(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
uint32_t vboy_state::screen_update_right(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
bitmap.fill(m_palette->pen(m_vip_regs.BKCOL), cliprect);
bitmap.fill(m_palette->pen(m_vip_io.BKCOL), cliprect);
int cur_spt;
if(!(m_vip_regs.DPCTRL & 2)) /* Don't bother if screen is off */
if(!(m_vip_io.DPCTRL & 2)) /* Don't bother if screen is off */
return 0;
cur_spt = 3;
@ -528,135 +533,116 @@ uint32_t vboy_state::screen_update_vboy_right(screen_device &screen, bitmap_ind1
*
*********************************/
uint32_t vboy_state::io_r(offs_t offset)
void vboy_state::io_map(address_map &map)
{
uint32_t value = 0x00;
// LPC (Link Port Control Reg)
// map(0x00 / 4, 0x00 / 4)
// LPC2 (Link Port Control Reg)
// map(0x04 / 4, 0x04 / 4)
// LPT (Link Port Transmit)
// map(0x08 / 4, 0x08 / 4)
// LPR (Link Port Receive) (read only)
// map(0x0c / 4, 0x0c / 4)
// KLB (Keypad Low Byte) (read only)
map(0x10 / 4, 0x10 / 4).lr8(NAME([this]() { return m_regs.klb; }));
// KHB (Keypad High Byte) (read only)
map(0x14 / 4, 0x14 / 4).lr8(NAME([this]() { return m_regs.khb; }));
// TLB (Timer Low Byte)
map(0x18 / 4, 0x18 / 4).lrw8(
NAME([this]() { return m_regs.tlb; }),
NAME([this](u8 data) {
m_regs.tlb = data;
m_timer.latch = m_regs.tlb | (m_timer.latch & 0xff00);
})
);
// THB (Timer High Byte)
map(0x1c / 4, 0x1c / 4).lrw8(
NAME([this]() { return m_regs.thb; }),
NAME([this](u8 data) {
m_regs.thb = data;
m_timer.latch = (m_regs.thb << 8) | (m_timer.latch & 0xff);
})
);
// TCR (Timer Control Reg)
map(0x20 / 4, 0x20 / 4).rw(FUNC(vboy_state::timer_control_r), FUNC(vboy_state::timer_control_w));
// WCR (Wait State Control Reg)
// according to docs: bits 2 to 7 are unused and set to 1.
map(0x24 / 4, 0x24 / 4).lrw8(
NAME([this]() { return m_regs.wcr | 0xfc; }),
NAME([this](u8 data) { m_regs.wcr = data | 0xfc; })
);
// KCR (Keypad Control Reg)
map(0x28 / 4, 0x28 / 4).rw(FUNC(vboy_state::keypad_control_r), FUNC(vboy_state::keypad_control_w));
switch ((offset << 2))
{
case 0x10: // KLB (Keypad Low Byte)
value = m_vboy_regs.klb; // 0x02 is always 1
break;
case 0x14: // KHB (Keypad High Byte)
value = m_vboy_regs.khb;
break;
case 0x18: // TLB (Timer Low Byte)
value = m_vboy_regs.tlb;
break;
case 0x1c: // THB (Timer High Byte)
value = m_vboy_regs.thb;
break;
case 0x20: // TCR (Timer Control Reg)
value = m_vboy_regs.tcr;
break;
case 0x24: // WCR (Wait State Control Reg)
value = m_vboy_regs.wcr;
break;
case 0x28: // KCR (Keypad Control Reg)
{
// attotime new_time = machine().time();
// if((new_time - m_input_latch_time) < m_maincpu->cycles_to_attotime(640))
// value |= machine().rand() & 2;
value = m_vboy_regs.kcr | 0x4c;
}
break;
case 0x00: // LPC (Link Port Control Reg)
case 0x04: // LPC2 (Link Port Control Reg)
case 0x08: // LPT (Link Port Transmit)
case 0x0c: // LPR (Link Port Receive)
default:
logerror("Unemulated read: offset %08x\n", 0x02000000 + (offset << 2));
break;
}
return value;
}
void vboy_state::io_w(offs_t offset, uint32_t data)
/*
* 111- ---- always 1
* ---x ---- timer select (1=20 us, 0=100 us)
* ---- x--- timer irq
* ---- -x-- resets timer zero flag
* ---- --x- timer is zero flag
* ---- ---x enables timer
*/
u8 vboy_state::timer_control_r()
{
switch (offset<<2)
return m_regs.tcr | 0xe4;
}
void vboy_state::timer_control_w(offs_t offset, u8 data)
{
if (!(data & 0x08))
m_maincpu->set_input_line(1, CLEAR_LINE);
if (data & 1)
{
case 0x0c: // LPR (Link Port Receive)
case 0x10: // KLB (Keypad Low Byte)
case 0x14: // KHB (Keypad High Byte)
//logerror("Ilegal write: offset %02x should be only read\n", offset);
break;
case 0x18: // TLB (Timer Low Byte)
m_vboy_regs.tlb = data;
m_vboy_timer.latch = m_vboy_regs.tlb | (m_vboy_timer.latch & 0xff00);
break;
case 0x1c: // THB (Timer High Byte)
m_vboy_regs.thb = data;
m_vboy_timer.latch = (m_vboy_regs.thb<<8) | (m_vboy_timer.latch & 0xff);
break;
case 0x20: // TCR (Timer Control Reg)
/*
111- ---- always 1
---x ---- timer select (1=20 us, 0=100 us)
---- x--- timer irq
---- -x-- resets timer zero flag
---- --x- timer is zero flag
---- ---x enables timer
*/
if (!(data & 0x08))
m_regs.tlb = m_timer.latch & 0xff;
m_regs.thb = m_timer.latch >> 8;
m_timer.count = m_timer.latch;
// only start timer if tcr & 1 is 1 and wasn't before?
if (!(m_regs.tcr & 1))
{
if (data & 0x10)
{
m_maincpu->set_input_line(1, CLEAR_LINE);
m_maintimer->adjust(attotime::from_hz(50000));
}
else
{
m_maintimer->adjust(attotime::from_hz(10000));
}
if (data & 1)
{
m_vboy_regs.tlb = m_vboy_timer.latch & 0xff;
m_vboy_regs.thb = m_vboy_timer.latch >> 8;
m_vboy_timer.count = m_vboy_timer.latch;
// only start timer if tcr & 1 is 1 and wasn't before?
if (!(m_vboy_regs.tcr & 1))
{
if (data & 0x10)
{
m_maintimer->adjust(attotime::from_hz(50000));
}
else
{
m_maintimer->adjust(attotime::from_hz(10000));
}
}
}
m_vboy_regs.tcr = (data & 0xfd) | (0xe4) | (m_vboy_regs.tcr & 2); // according to docs: bits 5, 6 & 7 are unused and set to 1, bit 1 is read only.
if(data & 4)
m_vboy_regs.tcr &= 0xfd;
break;
case 0x24: // WCR (Wait State Control Reg)
m_vboy_regs.wcr = data | 0xfc; // according to docs: bits 2 to 7 are unused and set to 1.
break;
case 0x28: // KCR (Keypad Control Reg)
if (data & 0x04 )
{
m_vboy_regs.klb = (ioport("INPUT")->read() & 0x00ff);
m_vboy_regs.khb = (ioport("INPUT")->read() & 0xff00) >> 8;
//m_input_latch_time = machine().time();
}
if (data & 1)
{
m_vboy_regs.klb = 0;
m_vboy_regs.khb = 0;
//m_input_latch_time = attotime::zero;
}
m_vboy_regs.kcr = (data | 0x48) & 0xfd; // according to docs: bit 6 & bit 3 are unused and set to 1, bit 1 is read only.
break;
case 0x00: // LPC (Link Port Control Reg)
case 0x04: // LPC2 (Link Port Control Reg)
case 0x08: // LPT (Link Port Transmit)
default:
logerror("Unemulated write: offset %08x, data %04x\n", 0x02000000 + (offset << 2), data);
break;
}
}
m_regs.tcr = (data & 0xfd) | (0xe4) | (m_regs.tcr & 2); // according to docs: bits 5, 6 & 7 are unused and set to 1, bit 1 is read only.
if(data & 4)
m_regs.tcr &= 0xfd;
}
u8 vboy_state::keypad_control_r()
{
return m_regs.kcr | 0x4c;
}
void vboy_state::keypad_control_w(offs_t offset, u8 data)
{
if (data & 0x04 )
{
m_regs.klb = (ioport("INPUT")->read() & 0x00ff);
m_regs.khb = (ioport("INPUT")->read() & 0xff00) >> 8;
//m_input_latch_time = machine().time();
}
if (data & 1)
{
m_regs.klb = 0;
m_regs.khb = 0;
//m_input_latch_time = attotime::zero;
}
// according to docs: bit 6 & bit 3 are unused and set to 1, bit 1 is read only.
m_regs.kcr = (data | 0x48) & 0xfd;
}
@ -665,17 +651,40 @@ void vboy_state::io_w(offs_t offset, uint32_t data)
* VIP
*
*********************************/
/*
TODO: brightness presumably isn't a linear algorithm, also REST needs to be taken into account (needs a working example)
*/
void vboy_state::m_set_brightness()
void vboy_state::vip_map(address_map &map)
{
map(0x00000000, 0x00005fff).rw(FUNC(vboy_state::lfb0_r), FUNC(vboy_state::lfb0_w)); // L frame buffer 0
map(0x00006000, 0x00007fff).rw(FUNC(vboy_state::font0_r), FUNC(vboy_state::font0_w)); // Font 0-511
map(0x00008000, 0x0000dfff).rw(FUNC(vboy_state::lfb1_r), FUNC(vboy_state::lfb1_w)); // L frame buffer 1
map(0x0000e000, 0x0000ffff).rw(FUNC(vboy_state::font1_r), FUNC(vboy_state::font1_w)); // Font 512-1023
map(0x00010000, 0x00015fff).rw(FUNC(vboy_state::rfb0_r), FUNC(vboy_state::rfb0_w)); // R frame buffer 0
map(0x00016000, 0x00017fff).rw(FUNC(vboy_state::font2_r), FUNC(vboy_state::font2_w)); // Font 1024-1535
map(0x00018000, 0x0001dfff).rw(FUNC(vboy_state::rfb1_r), FUNC(vboy_state::rfb1_w)); // R frame buffer 1
map(0x0001e000, 0x0001ffff).rw(FUNC(vboy_state::font3_r), FUNC(vboy_state::font3_w)); // Font 1536-2047
map(0x00020000, 0x0003ffff).rw(FUNC(vboy_state::bgmap_r), FUNC(vboy_state::bgmap_w)); // VIPC memory
//map(0x00040000, 0x0005ffff).ram(); // VIPC
map(0x0005f800, 0x0005f87f).rw(FUNC(vboy_state::vip_io_r), FUNC(vboy_state::vip_io_w));
map(0x00078000, 0x00079fff).rw(FUNC(vboy_state::font0_r), FUNC(vboy_state::font0_w)); // Font 0-511 mirror
map(0x0007a000, 0x0007bfff).rw(FUNC(vboy_state::font1_r), FUNC(vboy_state::font1_w)); // Font 512-1023 mirror
map(0x0007c000, 0x0007dfff).rw(FUNC(vboy_state::font2_r), FUNC(vboy_state::font2_w)); // Font 1024-1535 mirror
map(0x0007e000, 0x0007ffff).rw(FUNC(vboy_state::font3_r), FUNC(vboy_state::font3_w)); // Font 1536-2047 mirror
}
// TODO: verify against real HW
// - brightness presumably isn't a linear algorithm
// - REST needs to be taken into account (needs a working example)
void vboy_state::set_brightness()
{
int a,b,c;
//d = (m_vip_regs.BRTA + m_vip_regs.BRTB + m_vip_regs.BRTC + m_vip_regs.REST);
a = (0xff * (m_vip_regs.BRTA)) / 0x80;
b = (0xff * (m_vip_regs.BRTA + m_vip_regs.BRTB)) / 0x80;
c = (0xff * (m_vip_regs.BRTA + m_vip_regs.BRTB + m_vip_regs.BRTC)) / 0x80;
//d = (m_vip_io.BRTA + m_vip_io.BRTB + m_vip_io.BRTC + m_vip_io.REST);
a = (0xff * (m_vip_io.BRTA)) / 0x80;
b = (0xff * (m_vip_io.BRTA + m_vip_io.BRTB)) / 0x80;
c = (0xff * (m_vip_io.BRTA + m_vip_io.BRTB + m_vip_io.BRTC)) / 0x80;
if(a < 0) { a = 0; }
if(b < 0) { b = 0; }
@ -684,19 +693,19 @@ void vboy_state::m_set_brightness()
if(b > 0xff) { b = 0xff; }
if(c > 0xff) { c = 0xff; }
// popmessage("%02x %02x %02x %02x",m_vip_regs.BRTA,m_vip_regs.BRTB,m_vip_regs.BRTC,m_vip_regs.REST);
// popmessage("%02x %02x %02x %02x",m_vip_io.BRTA,m_vip_io.BRTB,m_vip_io.BRTC,m_vip_io.REST);
m_palette->set_pen_color(1, a,0,0);
m_palette->set_pen_color(2, b,0,0);
m_palette->set_pen_color(3, c,0,0);
}
uint16_t vboy_state::vip_r(offs_t offset)
uint16_t vboy_state::vip_io_r(offs_t offset)
{
switch(offset << 1) {
case 0x00: //INTPND
return m_vip_regs.INTPND;
return m_vip_io.INTPND;
case 0x02: //INTENB
return m_vip_regs.INTENB;
return m_vip_io.INTENB;
case 0x04: //INTCLR
logerror("Error reading INTCLR\n");
break;
@ -717,9 +726,9 @@ uint16_t vboy_state::vip_r(offs_t offset)
{
uint16_t res;
res = m_vip_regs.DPCTRL & 0x0702;
res = m_vip_io.DPCTRL & 0x0702;
if(m_vip_regs.DPCTRL & 2)
if(m_vip_io.DPCTRL & 2)
{
if(m_row_num < 224/8)
{
@ -735,20 +744,20 @@ uint16_t vboy_state::vip_r(offs_t offset)
return res;
}
case 0x22: //DPCTRL
return m_vip_regs.DPCTRL;
return m_vip_io.DPCTRL;
case 0x24: //BRTA
return m_vip_regs.BRTA;
return m_vip_io.BRTA;
case 0x26: //BRTB
return m_vip_regs.BRTB;
return m_vip_io.BRTB;
case 0x28: //BRTC
return m_vip_regs.BRTC;
return m_vip_io.BRTC;
case 0x2A: //REST
return m_vip_regs.REST;
return m_vip_io.REST;
case 0x2E: //FRMCYC
return m_vip_regs.FRMCYC;
return m_vip_io.FRMCYC;
case 0x30: //CTA
printf("Read CTA\n");
return m_vip_regs.CTA;
return m_vip_io.CTA;
case 0x40: //XPSTTS, piXel Processor STaTuS
{
/*
@ -764,7 +773,7 @@ uint16_t vboy_state::vip_r(offs_t offset)
//printf("%d\n",row_num);
res = m_vip_regs.XPSTTS & 0x00f3; // empty ^^'
res = m_vip_io.XPSTTS & 0x00f3; // empty ^^'
res |= m_drawfb << 2;
if(m_row_num < 224/8)
@ -776,36 +785,36 @@ uint16_t vboy_state::vip_r(offs_t offset)
return res;
}
case 0x42: //XPCTRL
return m_vip_regs.XPCTRL;
return m_vip_io.XPCTRL;
case 0x44: //VER
printf("%08x read VER\n",m_maincpu->pc());
return m_vip_regs.VER;
return m_vip_io.VER;
case 0x48: //SPT0
return m_vip_regs.SPT[0];
return m_vip_io.SPT[0];
case 0x4A: //SPT1
return m_vip_regs.SPT[1];
return m_vip_io.SPT[1];
case 0x4C: //SPT2
return m_vip_regs.SPT[2];
return m_vip_io.SPT[2];
case 0x4E: //SPT3
return m_vip_regs.SPT[3];
return m_vip_io.SPT[3];
case 0x60: //GPLT0
return m_vip_regs.GPLT[0];
return m_vip_io.GPLT[0];
case 0x62: //GPLT1
return m_vip_regs.GPLT[1];
return m_vip_io.GPLT[1];
case 0x64: //GPLT2
return m_vip_regs.GPLT[2];
return m_vip_io.GPLT[2];
case 0x66: //GPLT3
return m_vip_regs.GPLT[3];
return m_vip_io.GPLT[3];
case 0x68: //JPLT0
return m_vip_regs.JPLT[0];
return m_vip_io.JPLT[0];
case 0x6A: //JPLT1
return m_vip_regs.JPLT[1];
return m_vip_io.JPLT[1];
case 0x6C: //JPLT2
return m_vip_regs.JPLT[2];
return m_vip_io.JPLT[2];
case 0x6E: //JPLT3
return m_vip_regs.JPLT[3];
return m_vip_io.JPLT[3];
case 0x70: //BKCOL
return m_vip_regs.BKCOL;
return m_vip_io.BKCOL;
default:
logerror("Unemulated read: addr %08x\n", offset * 2 + 0x0005f800);
break;
@ -813,7 +822,7 @@ uint16_t vboy_state::vip_r(offs_t offset)
return 0xffff;
}
void vboy_state::vip_w(offs_t offset, uint16_t data, uint16_t mem_mask)
void vboy_state::vip_io_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
if(mem_mask != 0xffff)
printf("%04x %02x\n",mem_mask,offset*2);
@ -833,15 +842,15 @@ void vboy_state::vip_w(offs_t offset, uint16_t data, uint16_t mem_mask)
logerror("Error writing INTPND\n");
break;
case 0x02: //INTENB
m_vip_regs.INTENB = data;
m_set_irq(0);
m_vip_io.INTENB = data;
set_irq(0);
//printf("%04x ENB\n",data);
break;
case 0x04: //INTCLR
m_vip_regs.INTPND &= ~data;
m_set_irq(0);
m_vip_io.INTPND &= ~data;
set_irq(0);
//else
// printf("%04x\n",m_vip_regs.INTPND);
// printf("%04x\n",m_vip_io.INTPND);
break;
case 0x20: //DPSTTS
logerror("Error writing DPSTTS\n");
@ -854,38 +863,38 @@ void vboy_state::vip_w(offs_t offset, uint16_t data, uint16_t mem_mask)
---- ---- ---- ---x DPRST (Resets the VIP internal counter)
*/
case 0x22: //DPCTRL
m_vip_regs.DPCTRL = data & 0x0702;
m_vip_io.DPCTRL = data & 0x0702;
if(data & 1)
{
m_vip_regs.INTPND &= 0xe000; // reset FRAME_START, GAME_START, RFB_END, LFB_END and SCAN_ERR irqs
m_set_irq(0);
m_vip_io.INTPND &= 0xe000; // reset FRAME_START, GAME_START, RFB_END, LFB_END and SCAN_ERR irqs
set_irq(0);
}
break;
case 0x24: //BRTA
m_vip_regs.BRTA = data;
m_set_brightness();
m_vip_io.BRTA = data;
set_brightness();
break;
case 0x26: //BRTB
m_vip_regs.BRTB = data;
m_set_brightness();
m_vip_io.BRTB = data;
set_brightness();
break;
case 0x28: //BRTC
m_vip_regs.BRTC = data;
m_set_brightness();
m_vip_io.BRTC = data;
set_brightness();
break;
case 0x2A: //REST
m_vip_regs.REST = data;
m_set_brightness();
m_vip_io.REST = data;
set_brightness();
if(data)
printf("%04x REST\n",data);
break;
case 0x2E: //FRMCYC
//printf("%d\n",data);
m_vip_regs.FRMCYC = data;
m_vip_io.FRMCYC = data;
break;
case 0x30: //CTA
m_vip_regs.CTA = data;
m_vip_io.CTA = data;
printf("%04x CTA\n",data);
break;
case 0x40: //XPSTTS
@ -896,58 +905,58 @@ void vboy_state::vip_w(offs_t offset, uint16_t data, uint16_t mem_mask)
---- ---- ---- --x-
---- ---- ---- ---x Reset Pixel Processor
*/
m_vip_regs.XPCTRL = data & 0x1f02;
m_vip_io.XPCTRL = data & 0x1f02;
//if(data & 0x1f00)
// printf("%04x SBCMP\n",data);
if(data & 1)
{
m_vip_regs.INTPND &= 0x1fff; // reset SB_HIT, XP_END and TIME_ERR irqs
m_set_irq(0);
m_vip_io.INTPND &= 0x1fff; // reset SB_HIT, XP_END and TIME_ERR irqs
set_irq(0);
}
break;
case 0x44: //VER
//m_vip_regs.VER = data;
//m_vip_io.VER = data;
break;
case 0x48: //SPT0
m_vip_regs.SPT[0] = data & 0x3ff;
m_vip_io.SPT[0] = data & 0x3ff;
break;
case 0x4A: //SPT1
m_vip_regs.SPT[1] = data & 0x3ff;
m_vip_io.SPT[1] = data & 0x3ff;
break;
case 0x4C: //SPT2
m_vip_regs.SPT[2] = data & 0x3ff;
m_vip_io.SPT[2] = data & 0x3ff;
break;
case 0x4E: //SPT3
m_vip_regs.SPT[3] = data & 0x3ff;
m_vip_io.SPT[3] = data & 0x3ff;
break;
case 0x60: //GPLT0
m_vip_regs.GPLT[0] = data;
m_vip_io.GPLT[0] = data;
break;
case 0x62: //GPLT1
m_vip_regs.GPLT[1] = data;
m_vip_io.GPLT[1] = data;
break;
case 0x64: //GPLT2
m_vip_regs.GPLT[2] = data;
m_vip_io.GPLT[2] = data;
break;
case 0x66: //GPLT3
m_vip_regs.GPLT[3] = data;
m_vip_io.GPLT[3] = data;
break;
case 0x68: //JPLT0
m_vip_regs.JPLT[0] = data & 0xfc;
m_vip_io.JPLT[0] = data & 0xfc;
break;
case 0x6A: //JPLT1
m_vip_regs.JPLT[1] = data & 0xfc;
m_vip_io.JPLT[1] = data & 0xfc;
break;
case 0x6C: //JPLT2
m_vip_regs.JPLT[2] = data & 0xfc;
m_vip_io.JPLT[2] = data & 0xfc;
break;
case 0x6E: //JPLT3
m_vip_regs.JPLT[3] = data & 0xfc;
m_vip_io.JPLT[3] = data & 0xfc;
break;
case 0x70: //BKCOL
m_vip_regs.BKCOL = data & 3;
m_vip_io.BKCOL = data & 3;
break;
default:
logerror("Unemulated write: addr %08x, data %04x\n", offset * 2 + 0x0005f800, data);
@ -997,12 +1006,12 @@ uint16_t vboy_state::font3_r(offs_t offset)
return READ_FONT(offset + 0x3000);
}
void vboy_state::vboy_bgmap_w(offs_t offset, uint16_t data, uint16_t mem_mask)
void vboy_state::bgmap_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
m_bgmap[offset] = data | (m_bgmap[offset] & (mem_mask ^ 0xffff));
}
uint16_t vboy_state::vboy_bgmap_r(offs_t offset)
uint16_t vboy_state::bgmap_r(offs_t offset)
{
return m_bgmap[offset];
}
@ -1017,36 +1026,27 @@ void vboy_state::rfb0_w(offs_t offset, uint8_t data) { m_r_frame_0[offset] = dat
void vboy_state::rfb1_w(offs_t offset, uint8_t data) { m_r_frame_1[offset] = data; }
void vboy_state::vboy_mem(address_map &map)
void vboy_state::vboy_map(address_map &map)
{
map.global_mask(0x07ffffff);
map(0x00000000, 0x00005fff).rw(FUNC(vboy_state::lfb0_r), FUNC(vboy_state::lfb0_w)); // L frame buffer 0
map(0x00006000, 0x00007fff).rw(FUNC(vboy_state::font0_r), FUNC(vboy_state::font0_w)); // Font 0-511
map(0x00008000, 0x0000dfff).rw(FUNC(vboy_state::lfb1_r), FUNC(vboy_state::lfb1_w)); // L frame buffer 1
map(0x0000e000, 0x0000ffff).rw(FUNC(vboy_state::font1_r), FUNC(vboy_state::font1_w)); // Font 512-1023
map(0x00010000, 0x00015fff).rw(FUNC(vboy_state::rfb0_r), FUNC(vboy_state::rfb0_w)); // R frame buffer 0
map(0x00016000, 0x00017fff).rw(FUNC(vboy_state::font2_r), FUNC(vboy_state::font2_w)); // Font 1024-1535
map(0x00018000, 0x0001dfff).rw(FUNC(vboy_state::rfb1_r), FUNC(vboy_state::rfb1_w)); // R frame buffer 1
map(0x0001e000, 0x0001ffff).rw(FUNC(vboy_state::font3_r), FUNC(vboy_state::font3_w)); // Font 1536-2047
map(0x00020000, 0x0003ffff).rw(FUNC(vboy_state::vboy_bgmap_r), FUNC(vboy_state::vboy_bgmap_w)); // VIPC memory
//map(0x00040000, 0x0005ffff).ram(); // VIPC
map(0x0005f800, 0x0005f87f).rw(FUNC(vboy_state::vip_r), FUNC(vboy_state::vip_w));
map(0x00078000, 0x00079fff).rw(FUNC(vboy_state::font0_r), FUNC(vboy_state::font0_w)); // Font 0-511 mirror
map(0x0007a000, 0x0007bfff).rw(FUNC(vboy_state::font1_r), FUNC(vboy_state::font1_w)); // Font 512-1023 mirror
map(0x0007c000, 0x0007dfff).rw(FUNC(vboy_state::font2_r), FUNC(vboy_state::font2_w)); // Font 1024-1535 mirror
map(0x0007e000, 0x0007ffff).rw(FUNC(vboy_state::font3_r), FUNC(vboy_state::font3_w)); // Font 1536-2047 mirror
map(0x00000000, 0x0007ffff).m(FUNC(vboy_state::vip_map));
map(0x01000000, 0x010005ff).rw("vbsnd", FUNC(vboysnd_device::read), FUNC(vboysnd_device::write));
map(0x02000000, 0x0200002b).mirror(0x0ffff00).rw(FUNC(vboy_state::io_r), FUNC(vboy_state::io_w)); // Hardware control registers mask 0xff
map(0x02000000, 0x020000ff).mirror(0x0ffff00).m(FUNC(vboy_state::io_map)).umask32(0x000000ff);
//map(0x04000000, 0x04ffffff) cartslot EXP
map(0x05000000, 0x0500ffff).mirror(0x0ff0000).ram().share("wram");// Main RAM - 64K mask 0xffff
//map(0x06000000, 0x06ffffff) cartslot CHIP
//map(0x07000000, 0x07ffffff) cartslot ROM
}
void vboy_state::vboy_io(address_map &map)
{
map.global_mask(0x07ffffff);
map(0x00000000, 0x0007ffff).m(FUNC(vboy_state::vip_map));
map(0x01000000, 0x010005ff).rw("vbsnd", FUNC(vboysnd_device::read), FUNC(vboysnd_device::write));
map(0x02000000, 0x020000ff).mirror(0x0ffff00).m(FUNC(vboy_state::io_map)).umask32(0x000000ff);
// TODO: verify if ROM/RAM mirrors on I/O space (nesterfb)
}
/* Input ports */
static INPUT_PORTS_START( vboy )
PORT_START("INPUT")
@ -1072,46 +1072,46 @@ INPUT_PORTS_END
void vboy_state::machine_reset()
{
/* Initial values taken from Reality Boy, to be verified when emulation improves */
m_vboy_regs.lpc = 0x6d;
m_vboy_regs.lpc2 = 0xff;
m_vboy_regs.lpt = 0x00;
m_vboy_regs.lpr = 0x00;
m_vboy_regs.klb = 0x00;
m_vboy_regs.khb = 0x00;
m_vboy_regs.tlb = 0xff;
m_vboy_regs.thb = 0xff;
m_vboy_regs.tcr = 0xe4;
m_vboy_regs.wcr = 0xfc;
m_vboy_regs.kcr = 0x4c | 0x80;
m_vip_regs.DPCTRL = 2; // ssquash relies on this at boot otherwise no frame_start irq is fired
m_regs.lpc = 0x6d;
m_regs.lpc2 = 0xff;
m_regs.lpt = 0x00;
m_regs.lpr = 0x00;
m_regs.klb = 0x00;
m_regs.khb = 0x00;
m_regs.tlb = 0xff;
m_regs.thb = 0xff;
m_regs.tcr = 0xe4;
m_regs.wcr = 0xfc;
m_regs.kcr = 0x4c | 0x80;
m_vip_io.DPCTRL = 2; // ssquash relies on this at boot otherwise no frame_start irq is fired
m_displayfb = 0;
m_drawfb = 0;
m_vboy_timer.count = 0;
m_timer.count = 0;
m_maintimer->adjust(attotime::never);
}
void vboy_state::m_timer_tick()
TIMER_DEVICE_CALLBACK_MEMBER(vboy_state::timer_main_tick)
{
if(m_vboy_timer.count > 0)
if(m_timer.count > 0)
{
m_vboy_timer.count--;
m_vboy_regs.tlb = m_vboy_timer.count & 0xff;
m_vboy_regs.thb = m_vboy_timer.count >> 8;
m_timer.count--;
m_regs.tlb = m_timer.count & 0xff;
m_regs.thb = m_timer.count >> 8;
}
if (m_vboy_timer.count == 0)
if (m_timer.count == 0)
{
m_vboy_timer.count = m_vboy_timer.latch;
m_vboy_regs.tcr |= 0x02;
if(m_vboy_regs.tcr & 8)
m_timer.count = m_timer.latch;
m_regs.tcr |= 0x02;
if(m_regs.tcr & 8)
{
m_maincpu->set_input_line(1, ASSERT_LINE);
}
}
if (m_vboy_regs.tcr & 0x10)
if (m_regs.tcr & 0x10)
{
m_maintimer->adjust(attotime::from_hz(50000));
}
@ -1121,14 +1121,9 @@ void vboy_state::m_timer_tick()
}
}
TIMER_DEVICE_CALLBACK_MEMBER(vboy_state::timer_main_tick)
{
m_timer_tick();
}
TIMER_DEVICE_CALLBACK_MEMBER(vboy_state::timer_pad_tick)
{
if((m_vboy_regs.kcr & 0x80) == 0)
if((m_regs.kcr & 0x80) == 0)
m_maincpu->set_input_line(0, HOLD_LINE);
}
@ -1140,37 +1135,37 @@ void vboy_state::vboy_palette(palette_device &palette) const
palette.set_pen_color(3, rgb_t::black());
}
void vboy_state::m_set_irq(uint16_t irq_vector)
void vboy_state::set_irq(uint16_t irq_vector)
{
m_vip_regs.INTPND |= irq_vector;
m_vip_io.INTPND |= irq_vector;
if(m_vip_regs.INTENB & m_vip_regs.INTPND)
if(m_vip_io.INTENB & m_vip_io.INTPND)
m_maincpu->set_input_line(4, ASSERT_LINE);
if((m_vip_regs.INTENB & m_vip_regs.INTPND) == 0)
if((m_vip_io.INTENB & m_vip_io.INTPND) == 0)
m_maincpu->set_input_line(4, CLEAR_LINE);
}
/* TODO: obviously all of this needs clean-ups and better implementation ... */
void vboy_state::m_scanline_tick(int scanline, uint8_t screen_type)
void vboy_state::scanline_tick(int scanline, uint8_t screen_type)
{
if(screen_type == 0)
m_row_num = (scanline / 8) & 0x1f;
if(scanline == 0)
{
if(m_vip_regs.DPCTRL & 2)
m_set_irq(0x0010); // FRAME_START
if(m_vip_io.DPCTRL & 2)
set_irq(0x0010); // FRAME_START
m_frame_count++;
if(m_frame_count > m_vip_regs.FRMCYC)
if(m_frame_count > m_vip_io.FRMCYC)
{
m_set_irq(0x0008); // GAME_START
set_irq(0x0008); // GAME_START
m_frame_count = 0;
}
if(m_vip_regs.DPCTRL & 2)
if(m_vip_io.DPCTRL & 2)
m_displayfb ^= 1;
}
@ -1180,23 +1175,23 @@ void vboy_state::m_scanline_tick(int scanline, uint8_t screen_type)
m_drawfb = 1;
else
m_drawfb = 2;
m_set_irq(0x4000); // XPEND
set_irq(0x4000); // XPEND
}
if(scanline == 232)
{
m_drawfb = 0;
m_set_irq(0x0002); // LFBEND
set_irq(0x0002); // LFBEND
}
if(scanline == 240)
{
m_set_irq(0x0004); // RFBEND
set_irq(0x0004); // RFBEND
}
if(m_row_num == ((m_vip_regs.XPCTRL & 0x1f00) >> 8))
if(m_row_num == ((m_vip_io.XPCTRL & 0x1f00) >> 8))
{
m_set_irq(0x2000); // SBHIT
set_irq(0x2000); // SBHIT
}
}
@ -1205,7 +1200,7 @@ TIMER_DEVICE_CALLBACK_MEMBER(vboy_state::vboy_scanlineL)
{
int scanline = param;
m_scanline_tick(scanline,0);
scanline_tick(scanline,0);
}
#if 0
@ -1213,7 +1208,7 @@ TIMER_DEVICE_CALLBACK_MEMBER(vboy_state::vboy_scanlineR)
{
int scanline = param;
//m_scanline_tick(scanline,1);
//scanline_tick(scanline,1);
}
#endif
@ -1222,7 +1217,8 @@ void vboy_state::vboy(machine_config &config)
{
/* basic machine hardware */
V810(config, m_maincpu, XTAL(20'000'000));
m_maincpu->set_addrmap(AS_PROGRAM, &vboy_state::vboy_mem);
m_maincpu->set_addrmap(AS_PROGRAM, &vboy_state::vboy_map);
m_maincpu->set_addrmap(AS_IO, &vboy_state::vboy_io);
TIMER(config, "scantimer_l").configure_scanline(FUNC(vboy_state::vboy_scanlineL), "3dleft", 0, 1);
//TIMER(config, "scantimer_r").configure_scanline(FUNC(vboy_state::vboy_scanlineR), "3dright", 0, 1);
@ -1240,13 +1236,13 @@ void vboy_state::vboy(machine_config &config)
/* Left screen */
screen_device &lscreen(SCREEN(config, "3dleft", SCREEN_TYPE_RASTER));
lscreen.set_raw(XTAL(20'000'000)/2,757,0,384,264,0,224);
lscreen.set_screen_update(FUNC(vboy_state::screen_update_vboy_left));
lscreen.set_screen_update(FUNC(vboy_state::screen_update_left));
lscreen.set_palette(m_palette);
/* Right screen */
screen_device &rscreen(SCREEN(config, "3dright", SCREEN_TYPE_RASTER));
rscreen.set_raw(XTAL(20'000'000)/2,757,0,384,264,0,224);
rscreen.set_screen_update(FUNC(vboy_state::screen_update_vboy_right));
rscreen.set_screen_update(FUNC(vboy_state::screen_update_right));
rscreen.set_palette(m_palette);
/* cartridge */