summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/drivers/nes_sh6578.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/drivers/nes_sh6578.cpp')
-rw-r--r--src/mame/drivers/nes_sh6578.cpp458
1 files changed, 401 insertions, 57 deletions
diff --git a/src/mame/drivers/nes_sh6578.cpp b/src/mame/drivers/nes_sh6578.cpp
index 4d6ab147ed7..e3407e7f9c0 100644
--- a/src/mame/drivers/nes_sh6578.cpp
+++ b/src/mame/drivers/nes_sh6578.cpp
@@ -11,13 +11,22 @@
*/
#include "emu.h"
-#include "cpu/m6502/n2a03.h"
+#include "cpu/m6502/m6502.h"
+#include "sound/nes_apu.h"
#include "emupal.h"
#include "screen.h"
#include "speaker.h"
#include "machine/bankdev.h"
#include "machine/timer.h"
+#define LOG_DMA (1U << 1)
+#define LOG_PPU (1U << 0)
+
+//#define VERBOSE (LOG_PPU)
+#define VERBOSE (0)
+
+#include "logmacro.h"
+
class nes_sh6578_state : public driver_device
{
public:
@@ -28,10 +37,14 @@ public:
m_fullrom(*this, "fullrom"),
m_vram(*this, "vram"),
m_screen(*this, "screen"),
- m_palette(*this, "palette")
+ m_palette(*this, "palette"),
+ m_apu(*this, "nesapu"),
+ m_timer(*this, "timer"),
+ m_in(*this, "IN%u", 0U)
{ }
void nes_sh6578(machine_config& config);
+ void nes_sh6578_pal(machine_config& config);
void init_nes_sh6578();
@@ -43,12 +56,14 @@ protected:
WRITE8_MEMBER(sprite_dma_w);
private:
- required_device<n2a03_device> m_maincpu;
+ required_device<cpu_device> m_maincpu;
required_memory_bank m_bank;
required_device<address_map_bank_device> m_fullrom;
required_device<address_map_bank_device> m_vram;
required_device<screen_device> m_screen;
required_device<palette_device> m_palette;
+ required_device<nesapu_device> m_apu;
+ required_device<timer_device> m_timer;
rgb_t nespal_to_RGB(int color_intensity, int color_num);
@@ -80,12 +95,27 @@ private:
DECLARE_WRITE8_MEMBER(timing_setting_control_w);
DECLARE_WRITE8_MEMBER(initial_startup_w);
+ DECLARE_WRITE8_MEMBER(irq_mask_w);
+ DECLARE_WRITE8_MEMBER(timer_config_w);
+ DECLARE_WRITE8_MEMBER(timer_value_w);
DECLARE_WRITE8_MEMBER(write_ppu);
DECLARE_READ8_MEMBER(read_ppu);
DECLARE_WRITE8_MEMBER(write_palette);
DECLARE_READ8_MEMBER(read_palette);
+ DECLARE_READ8_MEMBER(io0_r);
+ DECLARE_READ8_MEMBER(io1_r);
+ DECLARE_WRITE8_MEMBER(io_w);
+
+ DECLARE_READ8_MEMBER(psg1_4014_r);
+ DECLARE_READ8_MEMBER(psg1_4015_r);
+ DECLARE_WRITE8_MEMBER(psg1_4015_w);
+ DECLARE_WRITE8_MEMBER(psg1_4017_w);
+ DECLARE_READ8_MEMBER(apu_read_mem);
+
+ DECLARE_WRITE_LINE_MEMBER(apu_irq);
+
int m_iniital_startup_state;
std::vector<uint8_t> m_palette_ram;
@@ -98,6 +128,18 @@ private:
uint8_t m_dma_length[2];
uint8_t m_2000;
+ uint8_t m_2001;
+ uint8_t m_2002;
+ uint8_t m_2003;
+ uint8_t m_2004;
+ uint16_t m_scrollreg;
+ bool m_scrollreg_firstwrite;
+
+ uint16_t m_vramaddr;
+ uint8_t m_2007;
+
+ uint8_t m_irqmask;
+
uint8_t m_colsel_pntstart;
TIMER_DEVICE_CALLBACK_MEMBER(scanline);
@@ -107,7 +149,18 @@ private:
void vram_map(address_map& map);
void nes_sh6578_map(address_map& map);
+ uint16_t get_tileaddress(uint8_t x, uint8_t y, bool ishigh);
+
uint32_t screen_update(screen_device& screen, bitmap_rgb32& bitmap, const rectangle& cliprect);
+
+ TIMER_DEVICE_CALLBACK_MEMBER(timer_expired);
+ int m_timerval;
+
+ // this might be game specific
+ uint8_t m_previo;
+ uint8_t m_iolatch[2];
+ bool m_isbanked;
+ required_ioport_array<2> m_in;
};
TIMER_DEVICE_CALLBACK_MEMBER(nes_sh6578_state::scanline)
@@ -159,14 +212,14 @@ READ8_MEMBER(nes_sh6578_state::dma_r)
{
switch (offset)
{
- case 0x00: logerror("%s: nes_sh6578_state::dma_r offset %01x : DMA Control : %02x\n", machine().describe_context(), offset); return m_dma_control;
- case 0x01: logerror("%s: nes_sh6578_state::dma_r offset %01x : DMA Bank Select : %02x\n", machine().describe_context(), offset); return m_dma_bank;
- case 0x02: logerror("%s: nes_sh6578_state::dma_r offset %01x : DMA Source Address Low : %02x\n", machine().describe_context(), offset); return m_dma_source[0];
- case 0x03: logerror("%s: nes_sh6578_state::dma_r offset %01x : DMA Source Address High : %02x\n", machine().describe_context(), offset); return m_dma_source[1];
- case 0x04: logerror("%s: nes_sh6578_state::dma_r offset %01x : DMA Destination Address Low : %02x\n", machine().describe_context(), offset); return m_dma_dest[0];
- case 0x05: logerror("%s: nes_sh6578_state::dma_r offset %01x : DMA Destination Address High : %02x\n", machine().describe_context(), offset); return m_dma_dest[1];
- case 0x06: logerror("%s: nes_sh6578_state::dma_r offset %01x : DMA Length Low : %02x\n", machine().describe_context(), offset); return m_dma_length[0];
- case 0x07: logerror("%s: nes_sh6578_state::dma_r offset %01x : DMA Length High : %02x\n", machine().describe_context(), offset); return m_dma_length[1];
+ case 0x00: LOGMASKED(LOG_DMA, "%s: nes_sh6578_state::dma_r offset %01x : DMA Control : %02x\n", machine().describe_context(), offset, m_dma_control); return m_dma_control & 0x7f;
+ case 0x01: LOGMASKED(LOG_DMA, "%s: nes_sh6578_state::dma_r offset %01x : DMA Bank Select\n", machine().describe_context(), offset); return m_dma_bank;
+ case 0x02: LOGMASKED(LOG_DMA, "%s: nes_sh6578_state::dma_r offset %01x : DMA Source Address Low\n", machine().describe_context(), offset); return m_dma_source[0];
+ case 0x03: LOGMASKED(LOG_DMA, "%s: nes_sh6578_state::dma_r offset %01x : DMA Source Address High\n", machine().describe_context(), offset); return m_dma_source[1];
+ case 0x04: LOGMASKED(LOG_DMA, "%s: nes_sh6578_state::dma_r offset %01x : DMA Destination Address Low\n", machine().describe_context(), offset); return m_dma_dest[0];
+ case 0x05: LOGMASKED(LOG_DMA, "%s: nes_sh6578_state::dma_r offset %01x : DMA Destination Address High\n", machine().describe_context(), offset); return m_dma_dest[1];
+ case 0x06: LOGMASKED(LOG_DMA, "%s: nes_sh6578_state::dma_r offset %01x : DMA Length Low\n", machine().describe_context(), offset); return m_dma_length[0];
+ case 0x07: LOGMASKED(LOG_DMA, "%s: nes_sh6578_state::dma_r offset %01x : DMA Length High\n", machine().describe_context(), offset); return m_dma_length[1];
}
return 0x00;
}
@@ -179,7 +232,7 @@ void nes_sh6578_state::do_dma()
uint16_t dma_dest = m_dma_dest[0] | (m_dma_dest[1] << 8);
uint16_t dma_length = m_dma_length[0] | (m_dma_length[1] << 8);
- logerror("Doing DMA :%02x bank:%02x: source:%04x dest:%04x length:%04x\n", m_dma_control, m_dma_bank, dma_source, dma_dest, dma_length);
+ LOGMASKED(LOG_DMA, "Doing DMA :%02x bank:%02x: source:%04x dest:%04x length:%04x\n", m_dma_control, m_dma_bank, dma_source, dma_dest, dma_length);
uint16_t realsourceaddress = dma_source;
uint16_t realdestaddress = dma_dest;
@@ -214,8 +267,11 @@ void nes_sh6578_state::do_dma()
realsourceaddress++;
realdestaddress++;
}
-
}
+
+ // but games seem to be making quite a few DMA writes with lengths that seem too large? buggy code?
+ //m_dma_length[0] = 0;
+ //m_dma_length[1] = 0;
}
WRITE8_MEMBER(nes_sh6578_state::dma_w)
@@ -223,43 +279,43 @@ WRITE8_MEMBER(nes_sh6578_state::dma_w)
switch (offset)
{
case 0x0:
- logerror("%s: nes_sh6578_state::dma_w offset %01x : DMA Control : %02x\n", machine().describe_context(), offset, data);
+ LOGMASKED(LOG_DMA, "%s: nes_sh6578_state::dma_w offset %01x : DMA Control : %02x\n", machine().describe_context(), offset, data);
m_dma_control = data;
do_dma();
break;
case 0x1:
- logerror("%s: nes_sh6578_state::dma_w offset %01x : DMA Bank Select : %02x\n", machine().describe_context(), offset, data);
+ LOGMASKED(LOG_DMA, "%s: nes_sh6578_state::dma_w offset %01x : DMA Bank Select : %02x\n", machine().describe_context(), offset, data);
m_dma_bank = data;
break;
case 0x2:
- logerror("%s: nes_sh6578_state::dma_w offset %01x : DMA Source Address Low : %02x\n", machine().describe_context(), offset, data);
+ LOGMASKED(LOG_DMA, "%s: nes_sh6578_state::dma_w offset %01x : DMA Source Address Low : %02x\n", machine().describe_context(), offset, data);
m_dma_source[0] = data;
break;
case 0x3:
- logerror("%s: nes_sh6578_state::dma_w offset %01x : DMA Source Address High : %02x\n", machine().describe_context(), offset, data);
+ LOGMASKED(LOG_DMA, "%s: nes_sh6578_state::dma_w offset %01x : DMA Source Address High : %02x\n", machine().describe_context(), offset, data);
m_dma_source[1] = data;
break;
case 0x4:
- logerror("%s: nes_sh6578_state::dma_w offset %01x : DMA Destination Address Low : %02x\n", machine().describe_context(), offset, data);
+ LOGMASKED(LOG_DMA, "%s: nes_sh6578_state::dma_w offset %01x : DMA Destination Address Low : %02x\n", machine().describe_context(), offset, data);
m_dma_dest[0] = data;
break;
case 0x5:
- logerror("%s: nes_sh6578_state::dma_w offset %01x : DMA Destination Address High : %02x\n", machine().describe_context(), offset, data);
+ LOGMASKED(LOG_DMA, "%s: nes_sh6578_state::dma_w offset %01x : DMA Destination Address High : %02x\n", machine().describe_context(), offset, data);
m_dma_dest[1] = data;
break;
case 0x6:
- logerror("%s: nes_sh6578_state::dma_w offset %01x : DMA Length Low : %02x\n", machine().describe_context(), offset, data);
+ LOGMASKED(LOG_DMA, "%s: nes_sh6578_state::dma_w offset %01x : DMA Length Low : %02x\n", machine().describe_context(), offset, data);
m_dma_length[0] = data;
break;
case 0x7:
- logerror("%s: nes_sh6578_state::dma_w offset %01x : DMA Length High : %02x\n", machine().describe_context(), offset, data);
+ LOGMASKED(LOG_DMA, "%s: nes_sh6578_state::dma_w offset %01x : DMA Length High : %02x\n", machine().describe_context(), offset, data);
m_dma_length[1] = data;
break;
}
@@ -306,6 +362,35 @@ WRITE8_MEMBER(nes_sh6578_state::initial_startup_w)
}
}
+WRITE8_MEMBER(nes_sh6578_state::irq_mask_w)
+{
+ m_irqmask = data;
+
+ if (m_irqmask & 0x80)
+ m_maincpu->set_input_line(0, CLEAR_LINE);
+}
+
+WRITE8_MEMBER(nes_sh6578_state::timer_config_w)
+{
+ logerror("%s: nes_sh6578_state::timer_config_w : %02x (at pos y: %d x: %d )\n", machine().describe_context(), data, m_screen->vpos(), m_screen->hpos() );
+
+ if ((data & 0x80) && (data & 0x20))
+ {
+ m_timer->adjust(m_screen->scan_period() * m_timerval);
+ }
+ else
+ {
+ m_timer->adjust(attotime::never);
+ }
+}
+
+WRITE8_MEMBER(nes_sh6578_state::timer_value_w)
+{
+ logerror("%s: nes_sh6578_state::timer_value_w : %02x\n", machine().describe_context(), data);
+ m_timerval = data;
+}
+
+
WRITE8_MEMBER(nes_sh6578_state::timing_setting_control_w)
{
logerror("%s: nes_sh6578_state::timing_setting_control_w : %02x\n", machine().describe_context(), data);
@@ -385,13 +470,13 @@ rgb_t nes_sh6578_state::nespal_to_RGB(int color_intensity, int color_num)
READ8_MEMBER(nes_sh6578_state::read_palette)
{
- logerror("%s: nes_sh6578_state::read_ppu : Palette Entry %02x\n", machine().describe_context(), offset);
+ //logerror("%s: nes_sh6578_state::read_ppu : Palette Entry %02x\n", machine().describe_context(), offset);
return m_palette_ram[offset];
}
WRITE8_MEMBER(nes_sh6578_state::write_palette)
{
- logerror("%s: nes_sh6578_state::write_ppu : Palette Entry %02x : %02x\n", machine().describe_context(), offset, data);
+ //logerror("%s: nes_sh6578_state::write_ppu : Palette Entry %02x : %02x\n", machine().describe_context(), offset, data);
m_palette_ram[offset] = data;
rgb_t col = nespal_to_RGB((data & 0x30) >> 4, data & 0x0f);
@@ -404,7 +489,7 @@ READ8_MEMBER(nes_sh6578_state::read_ppu)
switch (offset)
{
case 0x08:
- logerror("%s: nes_sh6578_state::read_ppu : Color Select & PNT Start Address\n", machine().describe_context());
+ LOGMASKED(LOG_PPU, "%s: nes_sh6578_state::read_ppu : Color Select & PNT Start Address\n", machine().describe_context());
return m_colsel_pntstart;
case 0x00:
@@ -420,8 +505,13 @@ READ8_MEMBER(nes_sh6578_state::read_ppu)
return ret;
}
+ case 0x01: return m_2001;
+ case 0x03: return m_2003;
+ case 0x04: return m_2004;
+ case 0x07: return m_2007;
+
default:
- //return ppu2c0x_device::read(space, offset);
+ LOGMASKED(LOG_PPU, "%s: nes_sh6578_state::read_ppu : unhandled offset %02x\n", machine().describe_context(), offset);
return 0x00;
}
}
@@ -431,13 +521,54 @@ WRITE8_MEMBER(nes_sh6578_state::write_ppu)
switch (offset)
{
case 0x08:
- logerror("%s: nes_sh6578_state::write_ppu : Color Select & PNT Start Address : %02x\n", machine().describe_context(), data);
+ LOGMASKED(LOG_PPU, "%s: nes_sh6578_state::write_ppu : Color Select & PNT Start Address : %02x\n", machine().describe_context(), data);
m_colsel_pntstart = data;
break;
- case 0x00:
- m_2000 = data;
+ case 0x00: m_2000 = data; LOGMASKED(LOG_PPU, "%s: nes_sh6578_state::write_ppu offset %02x : %02x\n", machine().describe_context(), offset, data); break;
+ case 0x01: m_2001 = data; LOGMASKED(LOG_PPU, "%s: nes_sh6578_state::write_ppu offset %02x : %02x\n", machine().describe_context(), offset, data); break;
+ case 0x02: m_2002 = data; LOGMASKED(LOG_PPU, "%s: nes_sh6578_state::write_ppu offset %02x : %02x\n", machine().describe_context(), offset, data); break;
+ case 0x03: m_2003 = data; LOGMASKED(LOG_PPU, "%s: nes_sh6578_state::write_ppu offset %02x : %02x\n", machine().describe_context(), offset, data); break;
+ case 0x04: m_2004 = data; LOGMASKED(LOG_PPU, "%s: nes_sh6578_state::write_ppu offset %02x : %02x\n", machine().describe_context(), offset, data); break;
+ case 0x05:
+ {
+ LOGMASKED(LOG_PPU, "%s: nes_sh6578_state::write_ppu offset %02x : %02x\n", machine().describe_context(), offset, data);
+ if (m_scrollreg_firstwrite)
+ {
+ m_scrollreg = (m_scrollreg & 0xff00) | data;
+ m_scrollreg_firstwrite = false;
+
+ }
+ else
+ {
+ m_scrollreg = (m_scrollreg & 0x00ff) | (data<<8);
+ m_scrollreg_firstwrite = true;
+ }
+
+ break;
+ }
+
+ case 0x06:
+ {
+ LOGMASKED(LOG_PPU, "%s: nes_sh6578_state::write_ppu offset %02x : %02x\n", machine().describe_context(), offset, data);
+ m_vramaddr <<= 8;
+ m_vramaddr = (m_vramaddr & 0xff00) | data;
+ logerror(" vram address is now %04x\n", m_vramaddr);
break;
+ }
+
+ case 0x07:
+ {
+ LOGMASKED(LOG_PPU, "%s: nes_sh6578_state::write_ppu offset %02x : %02x\n", machine().describe_context(), offset, data);
+ m_vram->write8(m_vramaddr, data);
+
+ if (m_2000 & 4)
+ m_vramaddr += 64; // big race and pioneer racing in ts_handy11 need this to be 64, not 32
+ else
+ m_vramaddr++;
+
+ break;
+ }
default:
break;
@@ -445,6 +576,75 @@ WRITE8_MEMBER(nes_sh6578_state::write_ppu)
}
}
+READ8_MEMBER(nes_sh6578_state::io0_r)
+{
+ uint8_t ret = m_iolatch[0] & 0x01;
+ m_iolatch[0] >>= 1;
+ return ret;
+}
+
+READ8_MEMBER(nes_sh6578_state::io1_r)
+{
+ uint8_t ret = m_iolatch[1] & 0x01;
+ m_iolatch[1] >>= 1;
+ return ret;
+}
+
+WRITE8_MEMBER(nes_sh6578_state::io_w)
+{
+ if ((data != 0x00) && (data != 0x01) && (data != 0x02) && (data != 0x03))
+ logerror("%s: io_w : unexpected value : %02x\n", machine().describe_context(), data);
+
+ if ((m_previo & 0x01) != (data & 0x01))
+ {
+ // latch on rising or falling?
+ if (!(data & 0x01))
+ {
+ m_iolatch[0] = m_in[0]->read();
+ m_iolatch[1] = m_in[1]->read();
+ }
+ }
+
+ if (m_isbanked)
+ {
+ m_bank->set_entry((data>>1)&1);
+ }
+
+ m_previo = data;
+}
+
+
+READ8_MEMBER(nes_sh6578_state::psg1_4014_r)
+{
+ return m_apu->read(0x14);
+}
+
+READ8_MEMBER(nes_sh6578_state::psg1_4015_r)
+{
+ return m_apu->read(0x15);
+}
+
+WRITE8_MEMBER(nes_sh6578_state::psg1_4015_w)
+{
+ m_apu->write(0x15, data);
+}
+
+WRITE8_MEMBER(nes_sh6578_state::psg1_4017_w)
+{
+ m_apu->write(0x17, data);
+}
+
+WRITE_LINE_MEMBER(nes_sh6578_state::apu_irq)
+{
+ // unimplemented
+}
+
+READ8_MEMBER(nes_sh6578_state::apu_read_mem)
+{
+ return m_maincpu->space(AS_PROGRAM).read_byte(offset);
+}
+
+
void nes_sh6578_state::nes_sh6578_map(address_map& map)
{
@@ -455,9 +655,19 @@ void nes_sh6578_state::nes_sh6578_map(address_map& map)
map(0x4014, 0x4014).w(FUNC(nes_sh6578_state::sprite_dma_w));
+ map(0x4000, 0x4013).rw(m_apu, FUNC(nesapu_device::read), FUNC(nesapu_device::write));
+ map(0x4014, 0x4014).r(FUNC(nes_sh6578_state::psg1_4014_r));
+ map(0x4015, 0x4015).rw(FUNC(nes_sh6578_state::psg1_4015_r), FUNC(nes_sh6578_state::psg1_4015_w));
+ map(0x4016, 0x4016).rw(FUNC(nes_sh6578_state::io0_r), FUNC(nes_sh6578_state::io_w));
+ map(0x4017, 0x4017).rw(FUNC(nes_sh6578_state::io1_r), FUNC(nes_sh6578_state::psg1_4017_w));
+
map(0x4020, 0x4020).w(FUNC(nes_sh6578_state::timing_setting_control_w));
map(0x4031, 0x4031).w(FUNC(nes_sh6578_state::initial_startup_w));
+ map(0x4032, 0x4032).w(FUNC(nes_sh6578_state::irq_mask_w));
+
+ map(0x4034, 0x4034).w(FUNC(nes_sh6578_state::timer_config_w));
+ map(0x4035, 0x4035).w(FUNC(nes_sh6578_state::timer_value_w));
map(0x4040, 0x4047).rw(FUNC(nes_sh6578_state::bankswitch_r), FUNC(nes_sh6578_state::bankswitch_w));
@@ -479,6 +689,18 @@ void nes_sh6578_state::nes_sh6578_map(address_map& map)
}
static INPUT_PORTS_START(nes_sh6578)
+ PORT_START("IN0")
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_PLAYER(1)
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_PLAYER(1)
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_SELECT ) PORT_PLAYER(1)
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_START ) PORT_PLAYER(1)
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_PLAYER(1) PORT_8WAY
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1) PORT_8WAY
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1) PORT_8WAY
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1) PORT_8WAY
+
+ PORT_START("IN1")
+ PORT_BIT( 0xff, IP_ACTIVE_HIGH, IPT_UNUSED )
INPUT_PORTS_END
void nes_sh6578_state::video_start()
@@ -496,12 +718,39 @@ void nes_sh6578_state::machine_reset()
m_palette_ram[i] = 0x00;
m_iniital_startup_state = 0;
+ m_bank->set_entry(0);
+
+ m_2000 = 0;
+ m_2001 = 0;
+ m_2002 = 0;
+ m_2003 = 0;
+ m_2004 = 0;
+ m_2007 = 0;
+
+ m_scrollreg = 0x00;
+ m_scrollreg_firstwrite = true;
+
+ m_colsel_pntstart = 0;
+
+ m_irqmask = 0xff;
+ m_timerval = 0x00;
}
void nes_sh6578_state::machine_start()
{
m_bank->configure_entry(0, memregion("maincpu")->base() + 0x0000000);
m_bank->set_entry(0);
+
+ if (memregion("maincpu")->bytes() == 0x200000)
+ {
+ m_isbanked = true;
+ m_bank->configure_entry(1, memregion("maincpu")->base() + 0x100000);
+ }
+ else
+ {
+ m_isbanked = false;
+ }
+
}
// SH6578 can address 20-bit address space (1MB of ROM)
@@ -513,21 +762,83 @@ void nes_sh6578_state::rom_map(address_map& map)
void nes_sh6578_state::vram_map(address_map& map)
{
map(0x0000, 0x27ff).ram();
+ map(0x2800, 0x7fff).nopr();
map(0x8000, 0xffff).ram();
}
+uint16_t nes_sh6578_state::get_tileaddress(uint8_t x, uint8_t y, bool ishigh)
+{
+ if (!ishigh)
+ {
+ x &= 0x3f; // can't be bigger than 64x64;
+ y &= 0x3f;
+
+ if (x & 0x20) // right hand side of tilemap
+ {
+ x &= 0x1f;
+ if (y & 0x20) // bottom of tilemap
+ {
+ y &= 0x1f;
+ return 0x1800 + (x * 2) + (y * 0x40);
+ }
+ else
+ {
+ //y &= 0x1f;
+ return 0x0800 + (x * 2) + (y * 0x40);
+ }
+ }
+ else // left hand side of tilemap
+ {
+ //x &= 0x1f;
+ if (y & 0x20) // bottom of tilemap
+ {
+ y &= 0x1f;
+ return 0x1000 + (x * 2) + (y * 0x40);
+ }
+ else
+ {
+ //y &= 0x1f;
+ return 0x0000 + (x * 2) + (y * 0x40);
+ }
+ }
+ }
+ else
+ {
+ x &= 0x1f;
+ y &= 0x1f;
+
+ return 0x2000 + (x * 2) + (y * 0x40);
+ }
+}
uint32_t nes_sh6578_state::screen_update(screen_device& screen, bitmap_rgb32& bitmap, const rectangle& cliprect)
{
- // nametable base depends on bits in 0x2008, it isn't fixed at 0x2000 as it is on a NES
- int address = 0;
const pen_t *paldata = m_palette->pens();
// pages are 32 tiles high, not 30 as on NES
- for (int y = 0; y < 32; y++)
+ for (int scanline = cliprect.min_y; scanline <= cliprect.max_y; scanline++)
{
+ int xscrollmsb = m_2000 & 0x1;
+ int yscrollmsb = (m_2000 & 0x2)>>1;
+
+ uint16_t yscroll = (m_scrollreg & 0xff00) >> 8;
+ yscroll |= (yscrollmsb << 8);
+
+ uint16_t xscroll = m_scrollreg & 0x00ff;
+ xscroll |= (xscrollmsb << 8);
+
+ int realy = scanline + yscroll;
+
+ int y = realy >> 3;
+ int tileline = realy & 7;
+
for (int x = 0; x < 32; x++)
{
+ int xtile = x + (xscroll >> 3);
+
+ // nametable base depends on bits in 0x2008, it isn't fixed at 0x2000 as it is on a NES
+ uint16_t address = get_tileaddress(xtile, y, (m_colsel_pntstart & 1) ? true : false);
+
// character gfx pointer and palette select are encoded in a pair of bytes, not using separate attribute table for palette
uint16_t tileaddr;
tileaddr = (m_vram->read8(address) << 0);
@@ -539,41 +850,54 @@ uint32_t nes_sh6578_state::screen_update(screen_device& screen, bitmap_rgb32& bi
tileaddr &= 0x0fff;
tileaddr <<= 4;
- for (int yy = 0; yy < 8; yy++)
- {
- uint32_t* destptr = &bitmap.pix32((y*8)+ yy);
-
- uint8_t plane0 = m_vram->read8(tileaddr+0);
- uint8_t plane1 = m_vram->read8(tileaddr+8);
- uint8_t plane2 = m_vram->read8(tileaddr+16);
- uint8_t plane3 = m_vram->read8(tileaddr+24);
- for (int xx = 0; xx < 8; xx++)
- {
- uint8_t pixval = ((plane0 >> (7-xx)) & 1) << 0;
- pixval |= ((plane1 >> (7-xx)) & 1) << 1;
- pixval |= ((plane2 >> (7-xx)) & 1) << 2;
- pixval |= ((plane3 >> (7-xx)) & 1) << 3;
+ uint32_t* destptr = &bitmap.pix32(scanline);
- pixval |= ((pal & 0xc) << 2);
+ uint8_t plane0 = m_vram->read8(tileaddr+0+tileline);
+ uint8_t plane1 = m_vram->read8(tileaddr+8+tileline);
+ uint8_t plane2 = m_vram->read8(tileaddr+16+tileline);
+ uint8_t plane3 = m_vram->read8(tileaddr+24+tileline);
- destptr[(x * 8) + xx] = paldata[pixval];
- }
+ for (int xx = 0; xx < 8; xx++)
+ {
+ uint8_t pixval = ((plane0 >> (7-xx)) & 1) << 0;
+ pixval |= ((plane1 >> (7-xx)) & 1) << 1;
+ pixval |= ((plane2 >> (7-xx)) & 1) << 2;
+ pixval |= ((plane3 >> (7-xx)) & 1) << 3;
- tileaddr++;
+ pixval |= ((pal & 0xc) << 2);
+ destptr[(x * 8) + xx] = paldata[pixval];
}
-
}
}
return 0;
}
+TIMER_DEVICE_CALLBACK_MEMBER(nes_sh6578_state::timer_expired)
+{
+ if (!(m_irqmask & 0x80))
+ {
+ //printf("timer expired on line %d\n", m_screen->vpos());
+ m_maincpu->set_input_line(0, ASSERT_LINE);
+ }
+
+ m_timer->adjust(attotime::never);
+}
+
+
+// from n2a03.h verify that it actually uses these
+#define N2A03_NTSC_XTAL XTAL(21'477'272)
+#define N2A03_PAL_XTAL XTAL(26'601'712)
+#define NTSC_APU_CLOCK (N2A03_NTSC_XTAL/12) /* 1.7897726666... MHz */
+#define PAL_APU_CLOCK (N2A03_PAL_XTAL/16) /* 1.662607 MHz */
+#define PALC_APU_CLOCK (N2A03_PAL_XTAL/15) /* 1.77344746666... MHz */
+
void nes_sh6578_state::nes_sh6578(machine_config& config)
{
/* basic machine hardware */
- N2A03(config, m_maincpu, NTSC_APU_CLOCK);
+ M6502(config, m_maincpu, NTSC_APU_CLOCK); // regular M6502 core, not N2A03?
m_maincpu->set_addrmap(AS_PROGRAM, &nes_sh6578_state::nes_sh6578_map);
ADDRESS_MAP_BANK(config, m_fullrom).set_map(&nes_sh6578_state::rom_map).set_options(ENDIANNESS_NATIVE, 8, 20, 0x100000);
@@ -588,15 +912,35 @@ void nes_sh6578_state::nes_sh6578(machine_config& config)
m_screen->set_size(32 * 8, 262);
m_screen->set_visarea(0 * 8, 32 * 8 - 1, 0 * 8, 30 * 8 - 1);
m_screen->set_screen_update(FUNC(nes_sh6578_state::screen_update));
+ m_screen->set_video_attributes(VIDEO_UPDATE_SCANLINE);
+
+ TIMER(config, m_timer).configure_periodic(FUNC(nes_sh6578_state::timer_expired), attotime::never);
PALETTE(config, m_palette).set_entries(0x40);
/* sound hardware */
SPEAKER(config, "mono").front_center();
- m_maincpu->add_route(ALL_OUTPUTS, "mono", 0.50);
+
+ // have to add the APU separately due to using M6502
+ NES_APU(config, m_apu, NTSC_APU_CLOCK);
+ m_apu->irq().set(FUNC(nes_sh6578_state::apu_irq));
+ m_apu->mem_read().set(FUNC(nes_sh6578_state::apu_read_mem));
+ m_apu->add_route(ALL_OUTPUTS, "mono", 0.50);
}
+void nes_sh6578_state::nes_sh6578_pal(machine_config& config)
+{
+ nes_sh6578(config);
+
+ m_maincpu->set_clock(PALC_APU_CLOCK);
+ m_apu->set_clock(PALC_APU_CLOCK);
+ m_screen->set_refresh_hz(50.0070);
+ m_screen->set_vblank_time(ATTOSECONDS_IN_USEC((113.66 / (PALC_APU_CLOCK.dvalue() / 1000000)) *
+ (310 - 291 + 1 + 2)));
+ m_screen->set_size(32 * 8, 312);
+ m_screen->set_visarea(0 * 8, 32 * 8 - 1, 0 * 8, 30 * 8 - 1);
+}
void nes_sh6578_state::init_nes_sh6578()
{
@@ -625,12 +969,12 @@ ROM_START( ablwikid )
ROM_END
-CONS( 1997, bandgpad, 0, 0, nes_sh6578, nes_sh6578, nes_sh6578_state, init_nes_sh6578, "Bandai", "Multi Game Player Gamepad", MACHINE_NOT_WORKING )
+CONS( 1997, bandgpad, 0, 0, nes_sh6578, nes_sh6578, nes_sh6578_state, init_nes_sh6578, "Bandai", "Multi Game Player Gamepad", MACHINE_NOT_WORKING )
// possibly newer than 2001
-CONS( 2001, ts_handy11, 0, 0, nes_sh6578, nes_sh6578, nes_sh6578_state, init_nes_sh6578, "Techno Source", "Handy Boy 11-in-1 (TV Play Power)", MACHINE_NOT_WORKING )
+CONS( 2001, ts_handy11, 0, 0, nes_sh6578, nes_sh6578, nes_sh6578_state, init_nes_sh6578, "Techno Source", "Handy Boy 11-in-1 (TV Play Power)", MACHINE_NOT_WORKING )
-CONS( 200?, cpatrolm, 0, 0, nes_sh6578, nes_sh6578, nes_sh6578_state, init_nes_sh6578, "<unknown>", "City Patrolman", MACHINE_NOT_WORKING )
+CONS( 200?, cpatrolm, 0, 0, nes_sh6578_pal, nes_sh6578, nes_sh6578_state, init_nes_sh6578, "TimeTop", "City Patrolman", MACHINE_NOT_WORKING )
-// this writes the 0x65 0x76 startup code to 0x4031, but the ROM is larger than expected, extra banking?
-CONS( 200?, ablwikid, 0, 0, nes_sh6578, nes_sh6578, nes_sh6578_state, init_nes_sh6578, "Advance Bright Ltd.", "Wikid Joystick", MACHINE_NOT_WORKING ) // or Wik!d Joystick
+// ROM is banked
+CONS( 200?, ablwikid, 0, 0, nes_sh6578_pal, nes_sh6578, nes_sh6578_state, init_nes_sh6578, "Advance Bright Ltd.", "Wikid Joystick", MACHINE_NOT_WORKING ) // or Wik!d Joystick