subhuntr.cpp: Start to flesh out the skeleton - still nowhere near close to working.

This commit is contained in:
Vas Crabb 2021-04-19 00:24:35 +10:00
parent 258f52ae8b
commit cf5985de0f

View File

@ -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,55 +34,241 @@ 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();
void subhuntr_palette(palette_device &palette) const;
uint32_t screen_update_subhuntr(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
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 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();
}
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::set_intreq(unsigned bit, u8 mask)
{
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::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);
}
}
@ -84,19 +280,21 @@ void subhuntr_state::video_start()
void subhuntr_state::subhuntr_map(address_map &map)
{
map.global_mask(0x1fff);
map.unmap_value_high();
map(0x0000, 0x0fff).rom();
map(0x1c00, 0x1fff).ram();
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));
}
void subhuntr_state::subhuntr_io_map(address_map &map)
{
}
void subhuntr_state::subhuntr_data_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::));
}
/***************************************************************************
@ -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; });
m_maincpu->sense_handler().set(m_screen, FUNC(screen_device::vblank));
m_maincpu->intack_handler().set(FUNC(subhuntr_state::intack_r));
//s2636_device &s2636(S2636(config, "s2636", 0));
//s2636.set_offsets(3, -21);
//s2636.add_route(ALL_OUTPUTS, "mono", 0.10);
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));
/* 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");
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));
GFXDECODE(config, "gfxdecode", "palette", gfx_subhuntr);
PALETTE(config, "palette", FUNC(subhuntr_state::subhuntr_palette), 26);
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));
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);
/* sound hardware */
SPEAKER(config, "mono").front_center();
/* discrete sound */
}
@ -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 )