summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2021-04-19 00:24:35 +1000
committer Vas Crabb <vas@vastheman.com>2021-04-19 00:24:35 +1000
commitcf5985de0f952995861bf278ec72bf08e15f63d7 (patch)
tree1c8f6f6cd62430cff54d48fda80291555fe4a27c
parent258f52ae8bdb340f8cff56bae428446f3639953a (diff)
subhuntr.cpp: Start to flesh out the skeleton - still nowhere near close to working.
-rw-r--r--src/mame/drivers/subhuntr.cpp366
1 files changed, 288 insertions, 78 deletions
diff --git a/src/mame/drivers/subhuntr.cpp b/src/mame/drivers/subhuntr.cpp
index efa2e43e19c..334a1604971 100644
--- a/src/mame/drivers/subhuntr.cpp
+++ b/src/mame/drivers/subhuntr.cpp
@@ -1,20 +1,30 @@
// license:BSD-3-Clause
-// copyright-holders:David Haywood
+// copyright-holders:Vas Crabb
/*
-QTY Type clock position function
-2x 2636 Programmable Video Interface
-1x 2650 OSC/2 = 1.7897725 MHz 8-bit Microprocessor - main
-1x oscillator 3.579545 MHz
+QTY Type clock position function
+1x 2621 B8 Universal Sync Generator (PAL)
+3x 2636 H5,L5,N5 Programmable Video Interface
+1x 2650 OSC/2 = 1.7897725 MHz 8-bit Microprocessor - main
+1x oscillator 3.579545 MHz
ROMs
QTY Type position status
-4x 2708 6F,6H,6L,6N dumped
-1x N82S115 2B dumped
+4x 2708 F7,H7,L7,N7 dumped
+1x N82S115 B2 dumped
RAMs
QTY Type position
-2x 2101
+4x 2112-2 G8,G9,H8,H9,L8,L9,M8,M9
+2x 2101-1 B4,C4
+
+Video uses approximate PAL timings derived from a 3.579MHz crystal
+using a 2621 USG (227 clocks per line, 43-clock HBLANK, 312 lines,
+43-line VBLANK). This gives a resolution of 184*269, which is used for
+the 2636 PVIs. The clock is doubled to 7.15MHz for the text layer,
+giving a resolution of 368*269. Screen raw parameters are derived by
+considering pixel/line zero to be the first period after the end of the
+horizontal/vertical sync pulse.
*/
@@ -24,80 +34,268 @@ QTY Type position
#include "emupal.h"
#include "screen.h"
#include "speaker.h"
+#include "tilemap.h"
+
+namespace {
class subhuntr_state : public driver_device
{
public:
- subhuntr_state(const machine_config &mconfig, device_type type, const char *tag)
+ subhuntr_state(machine_config const &mconfig, device_type type, char const *tag)
: driver_device(mconfig, type, tag)
, m_maincpu(*this, "maincpu")
+ , m_screen(*this, "screen")
+ , m_pvi1_h5(*this, "pvi1")
+ , m_pvi2_l5(*this, "pvi2")
+ , m_pvi3_n5(*this, "pvi3")
+ , m_gfx(*this, "gfxdecode")
+ , m_txtram(*this, "txtram")
+ , m_intreq_cnf(*this, "JMP_1_7")
{
}
void subhuntr(machine_config &config);
protected:
+ enum { TIMER_VIDEO };
+
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
virtual void machine_start() override;
virtual void machine_reset() override;
- virtual void video_start() override;
private:
- INTERRUPT_GEN_MEMBER(subhuntr_interrupt);
+ void txtram_w(offs_t offset, u8 data);
+ u8 intack_r();
+
+ DECLARE_WRITE_LINE_MEMBER(pvi1_intreq_w);
+ DECLARE_WRITE_LINE_MEMBER(pvi2_intreq_w);
+ DECLARE_WRITE_LINE_MEMBER(pvi3_intreq_w);
+
+ void palette_init(palette_device &palette) const;
+ u32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, rectangle const &cliprect);
+ TILE_GET_INFO_MEMBER(tile_info);
+ TIMER_CALLBACK_MEMBER(video_callback);
- void subhuntr_palette(palette_device &palette) const;
- uint32_t screen_update_subhuntr(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
+ void set_intreq(unsigned bit, u8 mask);
+ void clr_intreq(unsigned bit);
- void subhuntr_data_map(address_map &map);
- void subhuntr_io_map(address_map &map);
void subhuntr_map(address_map &map);
- required_device<s2650_device> m_maincpu;
+ required_device<s2650_device> m_maincpu;
+ required_device<screen_device> m_screen;
+ required_device<s2636_device> m_pvi1_h5;
+ required_device<s2636_device> m_pvi2_l5;
+ required_device<s2636_device> m_pvi3_n5;
+ required_device<gfxdecode_device> m_gfx;
+ required_shared_ptr<u8> m_txtram;
+
+ required_ioport m_intreq_cnf;
+
+ u8 m_intreqs = 0;
+
+ bitmap_ind16 m_bitmap;
+ emu_timer *m_video_timer = nullptr;
+ tilemap_t *m_tilemap = nullptr;
};
/***************************************************************************
- Video
+ Machine implementation
***************************************************************************/
-void subhuntr_state::subhuntr_palette(palette_device &palette) const
+void subhuntr_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ switch (id)
+ {
+ case TIMER_VIDEO:
+ video_callback(ptr, param);
+ break;
+ default:
+ throw emu_fatalerror("Unknown id in subhuntr_state::device_timer");
+ }
+}
+
+void subhuntr_state::machine_start()
+{
+ m_video_timer = timer_alloc(TIMER_VIDEO);
+ m_tilemap = &machine().tilemap().create(*m_gfx, tilemap_get_info_delegate(*this, FUNC(subhuntr_state::tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 32, 8);
+ m_tilemap->set_transparent_pen(0);
+
+ save_item(NAME(m_intreqs));
+
+ m_screen->register_screen_bitmap(m_bitmap);
+
+ m_video_timer->adjust(m_screen->time_until_pos(1, 0));
+}
+
+void subhuntr_state::machine_reset()
{
}
-uint32_t subhuntr_state::screen_update_subhuntr(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+void subhuntr_state::txtram_w(offs_t offset, u8 data)
{
+ if (m_txtram[offset] != data)
+ {
+ m_txtram[offset] = data;
+ m_tilemap->mark_tile_dirty(offset);
+ }
+}
+
+u8 subhuntr_state::intack_r()
+{
+ unsigned const source = count_leading_zeros(m_intreqs) - 24;
+ u8 const vector = ((m_intreq_cnf->read() & 0x01) ? 0x91 : 0x11) | (source << 1);
+ switch (source)
+ {
+ case 1:
+ m_pvi1_h5->write_intack(ASSERT_LINE);
+ m_pvi1_h5->write_intack(CLEAR_LINE);
+ break;
+ case 2:
+ m_pvi2_l5->write_intack(ASSERT_LINE);
+ m_pvi2_l5->write_intack(CLEAR_LINE);
+ break;
+ case 4:
+ m_pvi3_n5->write_intack(ASSERT_LINE);
+ m_pvi3_n5->write_intack(CLEAR_LINE);
+ break;
+ case 3:
+ case 5:
+ case 6:
+ clr_intreq(7 - source);
+ break;
+ }
+ return vector;
+}
+
+WRITE_LINE_MEMBER(subhuntr_state::pvi1_intreq_w)
+{
+ if (state) set_intreq(6, 0x02);
+ else clr_intreq(6);
+}
+
+WRITE_LINE_MEMBER(subhuntr_state::pvi2_intreq_w)
+{
+ if (state) set_intreq(5, 0x04);
+ else clr_intreq(5);
+}
+
+WRITE_LINE_MEMBER(subhuntr_state::pvi3_intreq_w)
+{
+ if (state) set_intreq(3, 0x08);
+ else clr_intreq(3);
+}
+
+void subhuntr_state::palette_init(palette_device &palette) const
+{
+ palette.set_pen_color(0, 0x00, 0x00, 0x00);
+ palette.set_pen_color(1, 0x00, 0xff, 0x00);
+ palette.set_pen_color(2, 0x00, 0x00, 0x00);
+ palette.set_pen_color(3, 0x00, 0xff, 0xff);
+ palette.set_pen_color(4, 0x00, 0x00, 0x00);
+ palette.set_pen_color(5, 0xff, 0xff, 0x00);
+ palette.set_pen_color(6, 0x00, 0x00, 0x00);
+ palette.set_pen_color(7, 0xff, 0xff, 0xff);
+}
+
+u32 subhuntr_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, rectangle const &cliprect)
+{
+ copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, cliprect);
return 0;
}
-void subhuntr_state::video_start()
+TILE_GET_INFO_MEMBER(subhuntr_state::tile_info)
{
+ u8 const tile = m_txtram[tile_index];
+ u8 const code = tile & 0x3f;
+ u8 const colour = (tile >> 6) & 0x03;
+ tileinfo.set(0, code, colour, 0);
}
+TIMER_CALLBACK_MEMBER(subhuntr_state::video_callback)
+{
+ int const y = m_screen->vpos();
-/***************************************************************************
+ if (!y)
+ {
+ m_pvi1_h5->render_first_line();
+ m_pvi2_l5->render_first_line();
+ m_pvi3_n5->render_first_line();
+ }
+ else
+ {
+ m_pvi1_h5->render_next_line();
+ m_pvi2_l5->render_next_line();
+ m_pvi3_n5->render_next_line();
+ }
- Memory Maps, I/O
+ u16 const *src1 = &m_pvi1_h5->bitmap().pix(y);
+ u16 const *src2 = &m_pvi2_l5->bitmap().pix(y);
+ u16 const *src3 = &m_pvi3_n5->bitmap().pix(y);
+ u16 *dst = &m_bitmap.pix(y);
+ for (unsigned x = 0; x < m_bitmap.width(); x++, src1++, src2++, src3++, dst++)
+ {
+ u16 const pvi_val = S2636_PIXEL_COLOR(*src1 | *src2 | *src3);
+ *dst = pvi_val;
+ if (S2636_IS_PIXEL_DRAWN(*src1) && S2636_IS_PIXEL_DRAWN(*src2)) set_intreq(4, 0x10);
+ if (S2636_IS_PIXEL_DRAWN(*src1) && S2636_IS_PIXEL_DRAWN(*src3)) set_intreq(2, 0x20);
+ if (S2636_IS_PIXEL_DRAWN(*src2) && S2636_IS_PIXEL_DRAWN(*src3)) set_intreq(1, 0x40);
+ }
-***************************************************************************/
+ m_video_timer->adjust(m_screen->time_until_pos(y + 1, 0));
+}
-void subhuntr_state::subhuntr_map(address_map &map)
+void subhuntr_state::set_intreq(unsigned bit, u8 mask)
{
- map(0x0000, 0x0fff).rom();
- map(0x1c00, 0x1fff).ram();
+ u8 const shifted = ((m_intreq_cnf->read() & mask) ? 1U : 0U) << bit;
+ if (shifted & ~m_intreqs)
+ {
+ if (!m_intreqs)
+ m_maincpu->set_input_line(INPUT_LINE_IRQ0, ASSERT_LINE);
+ m_intreqs |= shifted;
+ }
}
-void subhuntr_state::subhuntr_io_map(address_map &map)
+void subhuntr_state::clr_intreq(unsigned bit)
{
+ u8 const shifted = 1U << bit;
+ if (shifted & m_intreqs)
+ {
+ m_intreqs &= ~shifted;
+ if (!m_intreqs)
+ m_maincpu->set_input_line(INPUT_LINE_IRQ0, CLEAR_LINE);
+ }
}
-void subhuntr_state::subhuntr_data_map(address_map &map)
+
+/***************************************************************************
+
+ Memory Maps, I/O
+
+***************************************************************************/
+
+void subhuntr_state::subhuntr_map(address_map &map)
{
-// map(S2650_CTRL_PORT, S2650_CTRL_PORT).rw(FUNC(subhuntr_state::), FUNC(subhuntr_state::));
-// map(S2650_DATA_PORT, S2650_DATA_PORT).rw(FUNC(subhuntr_state::), FUNC(subhuntr_state::));
+ map.global_mask(0x1fff);
+ map.unmap_value_high();
+
+ map(0x0000, 0x0fff).rom();
+ map(0x1000, 0x10ff).mirror(0x0100).ram(); // G8/G9
+ map(0x1200, 0x12ff).mirror(0x0100).ram(); // H8/H9
+ map(0x1400, 0x14ff).mirror(0x0100).ram(); // L8/L9
+ map(0x1600, 0x16ff).mirror(0x0100).ram(); // M8/M9
+ map(0x1800, 0x18ff).mirror(0x0100).w(FUNC(subhuntr_state::txtram_w)).share(m_txtram); // B4/C4
+ map(0x1b00, 0x1bff).rw(m_pvi3_n5, FUNC(s2636_device::read_data), FUNC(s2636_device::write_data));
+ map(0x1d00, 0x1dff).rw(m_pvi2_l5, FUNC(s2636_device::read_data), FUNC(s2636_device::write_data));
+ // Some kind of I/O at 1e00-1eff (enabled by PVI1 CE2)
+ map(0x1f00, 0x1fff).rw(m_pvi1_h5, FUNC(s2636_device::read_data), FUNC(s2636_device::write_data));
}
+
/***************************************************************************
Inputs
@@ -105,6 +303,31 @@ void subhuntr_state::subhuntr_data_map(address_map &map)
***************************************************************************/
static INPUT_PORTS_START( subhuntr )
+
+ // Factory jumpers controlling interrupt masking
+ PORT_START("JMP_1_7")
+ PORT_CONFNAME(0x01, 0x00, "JMP1") // interrupt vector MSB select (indirect bit)
+ PORT_CONFSETTING(0x00, DEF_STR(Off))
+ PORT_CONFSETTING(0x01, DEF_STR(On))
+ PORT_CONFNAME(0x02, 0x02, "JMP2") // PVI1 VBLANK/completion interrupt enable
+ PORT_CONFSETTING(0x00, DEF_STR(Off))
+ PORT_CONFSETTING(0x02, DEF_STR(On))
+ PORT_CONFNAME(0x04, 0x04, "JMP3") // PVI2 VBLANK/completion interrupt enable
+ PORT_CONFSETTING(0x00, DEF_STR(Off))
+ PORT_CONFSETTING(0x04, DEF_STR(On))
+ PORT_CONFNAME(0x08, 0x08, "JMP4") // PVI3 VBLANK/completion interrupt enable
+ PORT_CONFSETTING(0x00, DEF_STR(Off))
+ PORT_CONFSETTING(0x08, DEF_STR(On))
+ PORT_CONFNAME(0x10, 0x10, "JMP5") // PVI1/PVI2 collision interrupt enable
+ PORT_CONFSETTING(0x00, DEF_STR(Off))
+ PORT_CONFSETTING(0x10, DEF_STR(On))
+ PORT_CONFNAME(0x20, 0x20, "JMP6") // PVI1/PVI3 collision interrupt enable
+ PORT_CONFSETTING(0x00, DEF_STR(Off))
+ PORT_CONFSETTING(0x20, DEF_STR(On))
+ PORT_CONFNAME(0x40, 0x40, "JMP7") // PVI2/PVI3 collision interrupt enable
+ PORT_CONFSETTING(0x00, DEF_STR(Off));
+ PORT_CONFSETTING(0x40, DEF_STR(On));
+
INPUT_PORTS_END
@@ -114,67 +337,52 @@ INPUT_PORTS_END
***************************************************************************/
-void subhuntr_state::machine_start()
-{
-}
-
-void subhuntr_state::machine_reset()
-{
-}
-
-INTERRUPT_GEN_MEMBER(subhuntr_state::subhuntr_interrupt)
-{
- m_maincpu->set_input_line(0, ASSERT_LINE);
-}
-
static const gfx_layout tiles8x8_layout =
{
8,8,
RGN_FRAC(1,1),
1,
{ 0 },
- { 0, 1, 2, 3, 4, 5, 6, 7 },
+ { 7, 6, 5, 4, 3, 2, 1, 0 },
{ 0*8,1*8,2*8,3*8,4*8,5*8,6*8,7*8 },
8*8
};
static GFXDECODE_START( gfx_subhuntr )
- GFXDECODE_ENTRY( "gfx1", 0, tiles8x8_layout, 0, 1 )
+ GFXDECODE_ENTRY("gfx1", 0, tiles8x8_layout, 0, 4)
GFXDECODE_END
void subhuntr_state::subhuntr(machine_config &config)
{
- /* basic machine hardware */
- S2650(config, m_maincpu, 14318180/4/2);
+ S2650(config, m_maincpu, 3.579545_MHz_XTAL/2);
m_maincpu->set_addrmap(AS_PROGRAM, &subhuntr_state::subhuntr_map);
- m_maincpu->set_addrmap(AS_IO, &subhuntr_state::subhuntr_io_map);
- m_maincpu->set_addrmap(AS_DATA, &subhuntr_state::subhuntr_data_map);
- m_maincpu->set_vblank_int("screen", FUNC(subhuntr_state::subhuntr_interrupt));
- m_maincpu->sense_handler().set("screen", FUNC(screen_device::vblank));
- m_maincpu->intack_handler().set([this]() { m_maincpu->set_input_line(0, CLEAR_LINE); return 0x03; });
-
- //s2636_device &s2636(S2636(config, "s2636", 0));
- //s2636.set_offsets(3, -21);
- //s2636.add_route(ALL_OUTPUTS, "mono", 0.10);
-
- /* video hardware */
- screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
- screen.set_video_attributes(VIDEO_ALWAYS_UPDATE);
- screen.set_refresh_hz(50);
- screen.set_vblank_time(ATTOSECONDS_IN_USEC(2500)); /* not accurate */
- screen.set_size(256, 256);
- screen.set_visarea(1*8, 29*8-1, 2*8, 32*8-1);
- screen.set_screen_update(FUNC(subhuntr_state::screen_update_subhuntr));
- screen.set_palette("palette");
-
- GFXDECODE(config, "gfxdecode", "palette", gfx_subhuntr);
- PALETTE(config, "palette", FUNC(subhuntr_state::subhuntr_palette), 26);
-
- /* sound hardware */
- SPEAKER(config, "mono").front_center();
+ m_maincpu->sense_handler().set(m_screen, FUNC(screen_device::vblank));
+ m_maincpu->intack_handler().set(FUNC(subhuntr_state::intack_r));
+
+ S2636(config, m_pvi1_h5, 3.579545_MHz_XTAL);
+ m_pvi1_h5->set_divider(2);
+ m_pvi1_h5->intreq_cb().set(FUNC(subhuntr_state::pvi1_intreq_w));
+
+ S2636(config, m_pvi2_l5, 3.579545_MHz_XTAL);
+ m_pvi2_l5->set_divider(2);
+ m_pvi2_l5->intreq_cb().set(FUNC(subhuntr_state::pvi2_intreq_w));
+
+ S2636(config, m_pvi3_n5, 3.579545_MHz_XTAL);
+ m_pvi3_n5->set_divider(2);
+ m_pvi3_n5->intreq_cb().set(FUNC(subhuntr_state::pvi3_intreq_w));
- /* discrete sound */
+ SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
+ m_screen->set_raw(3.579545_MHz_XTAL*2, 227*2, 21*2, 205*2, 312, 29, 298);
+ m_screen->set_palette("palette");
+ m_screen->set_screen_update(FUNC(subhuntr_state::screen_update));
+
+ GFXDECODE(config, m_gfx, "txtpal", gfx_subhuntr);
+
+ PALETTE(config, "palette", palette_device::RGB_3BIT);
+ PALETTE(config, "txtpal", FUNC(subhuntr_state::palette_init), 8);
+
+ SPEAKER(config, "mono").front_center();
}
@@ -183,13 +391,15 @@ void subhuntr_state::subhuntr(machine_config &config)
ROM_START( subhuntr )
ROM_REGION( 0x1000, "maincpu", 0 )
- ROM_LOAD( "mr21.6f", 0x0000, 0x0400, CRC(27847939) SHA1(e6b41b511fefac1e1e207eff2dac8c2963d47c5c) )
- ROM_LOAD( "mr22.6g", 0x0400, 0x0400, CRC(e9af1ee8) SHA1(451e88407a120444377a58b06b65152c57503533) )
- ROM_LOAD( "mr25.6l", 0x0800, 0x0400, CRC(8271c975) SHA1(c7192658b50d781ab1b94c2e8cb75c5be3539820) )
- ROM_LOAD( "mr24.6n", 0x0c00, 0x0400, CRC(385c4944) SHA1(84050b0356c9a3a36528dba768f2684e28c6c7c4) )
+ ROM_LOAD( "mr21.f7", 0x0000, 0x0400, CRC(27847939) SHA1(e6b41b511fefac1e1e207eff2dac8c2963d47c5c) )
+ ROM_LOAD( "mr22.g7", 0x0400, 0x0400, CRC(e9af1ee8) SHA1(451e88407a120444377a58b06b65152c57503533) )
+ ROM_LOAD( "mr25.l7", 0x0800, 0x0400, CRC(8271c975) SHA1(c7192658b50d781ab1b94c2e8cb75c5be3539820) )
+ ROM_LOAD( "mr24.n7", 0x0c00, 0x0400, CRC(385c4944) SHA1(84050b0356c9a3a36528dba768f2684e28c6c7c4) )
ROM_REGION( 0x0200, "gfx1", 0 )
- ROM_LOAD( "82s115.2b", 0x0000, 0x0200, CRC(6946c9de) SHA1(956b4bebe6960a73609deb75e1493c4127fd7f77) ) // ASCII, not much else
+ ROM_LOAD( "82s115.b2", 0x0000, 0x0200, CRC(6946c9de) SHA1(956b4bebe6960a73609deb75e1493c4127fd7f77) )
ROM_END
+} // anonymous namespace
+
GAME(1979, subhuntr, 0, subhuntr, subhuntr, subhuntr_state, empty_init, ROT0, "Model Racing", "Sub Hunter (Model Racing)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND )