mirror of
https://github.com/holub/mame
synced 2025-07-03 00:56:03 +03:00
atari/gauntlet.cpp, atari/jedi.cpp: consolidated drivers in single files
This commit is contained in:
parent
1e4dcf003c
commit
4a6c54dd5e
File diff suppressed because it is too large
Load Diff
@ -1,109 +0,0 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Aaron Giles
|
||||
/*************************************************************************
|
||||
|
||||
Atari Gauntlet hardware
|
||||
|
||||
*************************************************************************/
|
||||
#ifndef MAME_ATARI_GAUNTLET_H
|
||||
#define MAME_ATARI_GAUNTLET_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "machine/74259.h"
|
||||
#include "machine/gen_latch.h"
|
||||
#include "slapstic.h"
|
||||
#include "machine/timer.h"
|
||||
#include "atarimo.h"
|
||||
#include "sound/pokey.h"
|
||||
#include "sound/tms5220.h"
|
||||
#include "sound/ymopm.h"
|
||||
#include "screen.h"
|
||||
#include "tilemap.h"
|
||||
|
||||
class gauntlet_state : public driver_device
|
||||
{
|
||||
public:
|
||||
gauntlet_state(const machine_config &mconfig, device_type type, const char *tag) :
|
||||
driver_device(mconfig, type, tag),
|
||||
m_maincpu(*this, "maincpu"),
|
||||
m_audiocpu(*this, "audiocpu"),
|
||||
m_soundlatch(*this, "soundlatch"),
|
||||
m_mainlatch(*this, "mainlatch"),
|
||||
m_ym2151(*this, "ymsnd"),
|
||||
m_pokey(*this, "pokey"),
|
||||
m_tms5220(*this, "tms"),
|
||||
m_soundctl(*this, "soundctl"),
|
||||
m_slapstic(*this, "slapstic"),
|
||||
m_slapstic_bank(*this, "slapstic_bank"),
|
||||
m_gfxdecode(*this, "gfxdecode"),
|
||||
m_screen(*this, "screen"),
|
||||
m_playfield_tilemap(*this, "playfield"),
|
||||
m_alpha_tilemap(*this, "alpha"),
|
||||
m_xscroll(*this, "xscroll"),
|
||||
m_yscroll(*this, "yscroll"),
|
||||
m_mob(*this, "mob")
|
||||
{ }
|
||||
|
||||
void init_gauntlet();
|
||||
void init_vindctr2();
|
||||
void vindctr2(machine_config &config);
|
||||
void gauntlet(machine_config &config);
|
||||
void gaunt2p(machine_config &config);
|
||||
void gauntlet2(machine_config &config);
|
||||
|
||||
protected:
|
||||
virtual void video_start() override;
|
||||
|
||||
private:
|
||||
void video_int_ack_w(uint16_t data = 0);
|
||||
TIMER_DEVICE_CALLBACK_MEMBER(scanline_update);
|
||||
uint8_t sound_irq_ack_r();
|
||||
void sound_irq_ack_w(uint8_t data);
|
||||
DECLARE_WRITE_LINE_MEMBER(sound_reset_w);
|
||||
uint8_t switch_6502_r();
|
||||
DECLARE_WRITE_LINE_MEMBER(speech_squeak_w);
|
||||
DECLARE_WRITE_LINE_MEMBER(coin_counter_left_w);
|
||||
DECLARE_WRITE_LINE_MEMBER(coin_counter_right_w);
|
||||
void mixer_w(uint8_t data);
|
||||
void common_init();
|
||||
TILE_GET_INFO_MEMBER(get_alpha_tile_info);
|
||||
TILE_GET_INFO_MEMBER(get_playfield_tile_info);
|
||||
uint32_t screen_update_gauntlet(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
|
||||
void gauntlet_xscroll_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
|
||||
void gauntlet_yscroll_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
|
||||
|
||||
void gauntlet_base(machine_config &config);
|
||||
void main_map(address_map &map);
|
||||
void sound_map(address_map &map);
|
||||
|
||||
required_device<cpu_device> m_maincpu;
|
||||
required_device<cpu_device> m_audiocpu;
|
||||
required_device<generic_latch_8_device> m_soundlatch;
|
||||
required_device<generic_latch_8_device> m_mainlatch;
|
||||
required_device<ym2151_device> m_ym2151;
|
||||
required_device<pokey_device> m_pokey;
|
||||
required_device<tms5220_device> m_tms5220;
|
||||
required_device<ls259_device> m_soundctl;
|
||||
required_device<atari_slapstic_device> m_slapstic;
|
||||
required_memory_bank m_slapstic_bank;
|
||||
|
||||
required_device<gfxdecode_device> m_gfxdecode;
|
||||
required_device<screen_device> m_screen;
|
||||
required_device<tilemap_device> m_playfield_tilemap;
|
||||
required_device<tilemap_device> m_alpha_tilemap;
|
||||
required_shared_ptr<uint16_t> m_xscroll;
|
||||
required_shared_ptr<uint16_t> m_yscroll;
|
||||
required_device<atari_motion_objects_device> m_mob;
|
||||
|
||||
uint16_t m_sound_reset_val = 0;
|
||||
bool m_vindctr2_screen_refresh = false;
|
||||
uint8_t m_playfield_tile_bank = 0;
|
||||
uint8_t m_playfield_color_bank = 0;
|
||||
|
||||
static const atari_motion_objects_config s_mob_config;
|
||||
|
||||
void slapstic_tweak(offs_t offset, u16 &, u16);
|
||||
};
|
||||
|
||||
#endif // MAME_ATARI_GAUNTLET_H
|
@ -1,194 +0,0 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Aaron Giles
|
||||
/***************************************************************************
|
||||
|
||||
Atari Gauntlet hardware
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "gauntlet.h"
|
||||
|
||||
|
||||
|
||||
/*************************************
|
||||
*
|
||||
* Tilemap callbacks
|
||||
*
|
||||
*************************************/
|
||||
|
||||
TILE_GET_INFO_MEMBER(gauntlet_state::get_alpha_tile_info)
|
||||
{
|
||||
uint16_t data = m_alpha_tilemap->basemem_read(tile_index);
|
||||
int code = data & 0x3ff;
|
||||
int color = ((data >> 10) & 0x0f) | ((data >> 9) & 0x20);
|
||||
int opaque = data & 0x8000;
|
||||
tileinfo.set(1, code, color, opaque ? TILE_FORCE_LAYER0 : 0);
|
||||
}
|
||||
|
||||
|
||||
TILE_GET_INFO_MEMBER(gauntlet_state::get_playfield_tile_info)
|
||||
{
|
||||
uint16_t data = m_playfield_tilemap->basemem_read(tile_index);
|
||||
int code = ((m_playfield_tile_bank * 0x1000) + (data & 0xfff)) ^ 0x800;
|
||||
int color = 0x10 + (m_playfield_color_bank * 8) + ((data >> 12) & 7);
|
||||
tileinfo.set(0, code, color, (data >> 15) & 1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*************************************
|
||||
*
|
||||
* Video system start
|
||||
*
|
||||
*************************************/
|
||||
|
||||
const atari_motion_objects_config gauntlet_state::s_mob_config =
|
||||
{
|
||||
0, /* index to which gfx system */
|
||||
1, /* number of motion object banks */
|
||||
1, /* are the entries linked? */
|
||||
1, /* are the entries split? */
|
||||
0, /* render in reverse order? */
|
||||
0, /* render in swapped X/Y order? */
|
||||
0, /* does the neighbor bit affect the next object? */
|
||||
8, /* pixels per SLIP entry (0 for no-slip) */
|
||||
1, /* pixel offset for SLIPs */
|
||||
0, /* maximum number of links to visit/scanline (0=all) */
|
||||
|
||||
0x100, /* base palette entry */
|
||||
0x100, /* maximum number of colors */
|
||||
0, /* transparent pen index */
|
||||
|
||||
{{ 0,0,0,0x03ff }}, /* mask for the link */
|
||||
{{ 0x7fff,0,0,0 }}, /* mask for the code index */
|
||||
{{ 0,0x000f,0,0 }}, /* mask for the color */
|
||||
{{ 0,0xff80,0,0 }}, /* mask for the X position */
|
||||
{{ 0,0,0xff80,0 }}, /* mask for the Y position */
|
||||
{{ 0,0,0x0038,0 }}, /* mask for the width, in tiles*/
|
||||
{{ 0,0,0x0007,0 }}, /* mask for the height, in tiles */
|
||||
{{ 0,0,0x0040,0 }}, /* mask for the horizontal flip */
|
||||
{{ 0 }}, /* mask for the vertical flip */
|
||||
{{ 0 }}, /* mask for the priority */
|
||||
{{ 0 }}, /* mask for the neighbor */
|
||||
{{ 0 }}, /* mask for absolute coordinates */
|
||||
|
||||
{{ 0 }}, /* mask for the special value */
|
||||
0 /* resulting value to indicate "special" */
|
||||
};
|
||||
|
||||
void gauntlet_state::video_start()
|
||||
{
|
||||
/* modify the motion object code lookup table to account for the code XOR */
|
||||
std::vector<uint32_t> &codelookup = m_mob->code_lookup();
|
||||
for (auto & elem : codelookup)
|
||||
elem ^= 0x800;
|
||||
|
||||
/* set up the base color for the playfield */
|
||||
m_playfield_color_bank = m_vindctr2_screen_refresh ? 0 : 1;
|
||||
|
||||
/* save states */
|
||||
save_item(NAME(m_playfield_tile_bank));
|
||||
save_item(NAME(m_playfield_color_bank));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*************************************
|
||||
*
|
||||
* Horizontal scroll register
|
||||
*
|
||||
*************************************/
|
||||
|
||||
void gauntlet_state::gauntlet_xscroll_w(offs_t offset, uint16_t data, uint16_t mem_mask)
|
||||
{
|
||||
uint16_t oldxscroll = *m_xscroll;
|
||||
COMBINE_DATA(m_xscroll);
|
||||
|
||||
/* if something changed, force a partial update */
|
||||
if (*m_xscroll != oldxscroll)
|
||||
{
|
||||
m_screen->update_partial(m_screen->vpos());
|
||||
|
||||
/* adjust the scrolls */
|
||||
m_playfield_tilemap->set_scrollx(0, *m_xscroll);
|
||||
m_mob->set_xscroll(*m_xscroll & 0x1ff);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*************************************
|
||||
*
|
||||
* Vertical scroll/PF bank register
|
||||
*
|
||||
*************************************/
|
||||
|
||||
void gauntlet_state::gauntlet_yscroll_w(offs_t offset, uint16_t data, uint16_t mem_mask)
|
||||
{
|
||||
uint16_t oldyscroll = *m_yscroll;
|
||||
COMBINE_DATA(m_yscroll);
|
||||
|
||||
/* if something changed, force a partial update */
|
||||
if (*m_yscroll != oldyscroll)
|
||||
{
|
||||
m_screen->update_partial(m_screen->vpos());
|
||||
|
||||
/* if the bank changed, mark all tiles dirty */
|
||||
if (m_playfield_tile_bank != (*m_yscroll & 3))
|
||||
{
|
||||
m_playfield_tile_bank = *m_yscroll & 3;
|
||||
m_playfield_tilemap->mark_all_dirty();
|
||||
}
|
||||
|
||||
/* adjust the scrolls */
|
||||
m_playfield_tilemap->set_scrolly(0, *m_yscroll >> 7);
|
||||
m_mob->set_yscroll((*m_yscroll >> 7) & 0x1ff);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*************************************
|
||||
*
|
||||
* Main refresh
|
||||
*
|
||||
*************************************/
|
||||
|
||||
uint32_t gauntlet_state::screen_update_gauntlet(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
|
||||
{
|
||||
// start drawing
|
||||
m_mob->draw_async(cliprect);
|
||||
|
||||
/* draw the playfield */
|
||||
m_playfield_tilemap->draw(screen, bitmap, cliprect, 0, 0);
|
||||
|
||||
/* draw and merge the MO */
|
||||
bitmap_ind16 &mobitmap = m_mob->bitmap();
|
||||
for (const sparse_dirty_rect *rect = m_mob->first_dirty_rect(cliprect); rect != nullptr; rect = rect->next())
|
||||
for (int y = rect->top(); y <= rect->bottom(); y++)
|
||||
{
|
||||
uint16_t const *const mo = &mobitmap.pix(y);
|
||||
uint16_t *const pf = &bitmap.pix(y);
|
||||
for (int x = rect->left(); x <= rect->right(); x++)
|
||||
if (mo[x] != 0xffff)
|
||||
{
|
||||
/* verified via schematics:
|
||||
|
||||
MO pen 1 clears PF color bit 0x80
|
||||
*/
|
||||
if ((mo[x] & 0x0f) == 1)
|
||||
{
|
||||
/* Vindicators Part II has extra logic here for the bases */
|
||||
if (!m_vindctr2_screen_refresh || (mo[x] & 0xf0) != 0)
|
||||
pf[x] ^= 0x80;
|
||||
}
|
||||
else
|
||||
pf[x] = mo[x];
|
||||
}
|
||||
}
|
||||
|
||||
/* add the alpha on top */
|
||||
m_alpha_tilemap->draw(screen, bitmap, cliprect, 0, 0);
|
||||
return 0;
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Dan Boris, Aaron Giles
|
||||
// copyright-holders: Dan Boris, Aaron Giles
|
||||
|
||||
/***************************************************************************
|
||||
|
||||
Atari Return of the Jedi hardware
|
||||
@ -113,13 +114,598 @@
|
||||
***************************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
|
||||
#include "cpu/m6502/m6502.h"
|
||||
#include "machine/74259.h"
|
||||
#include "machine/adc0808.h"
|
||||
#include "machine/nvram.h"
|
||||
#include "machine/gen_latch.h"
|
||||
#include "machine/rescap.h"
|
||||
#include "machine/watchdog.h"
|
||||
#include "jedi.h"
|
||||
#include "machine/x2212.h"
|
||||
#include "sound/pokey.h"
|
||||
#include "sound/tms5220.h"
|
||||
|
||||
#include "emupal.h"
|
||||
#include "screen.h"
|
||||
#include "speaker.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
#define DEBUG_GFXDECODE 0 // GFX layout for debug
|
||||
|
||||
class jedi_state : public driver_device
|
||||
{
|
||||
public:
|
||||
jedi_state(const machine_config &mconfig, device_type type, const char *tag) :
|
||||
driver_device(mconfig, type, tag),
|
||||
m_backgroundram(*this, "backgroundram"),
|
||||
m_foregroundram(*this, "foregroundram"),
|
||||
m_spriteram(*this, "spriteram"),
|
||||
m_smoothing_table(*this, "smoothing_table"),
|
||||
m_tx_gfx(*this, "tx_gfx"),
|
||||
m_bg_gfx(*this, "bg_gfx"),
|
||||
m_spr_gfx(*this, "spr_gfx"),
|
||||
m_proms(*this, "proms"),
|
||||
m_maincpu(*this, "maincpu"),
|
||||
m_audiocpu(*this, "audiocpu"),
|
||||
m_soundlatch(*this, "soundlatch"),
|
||||
m_sacklatch(*this, "sacklatch"),
|
||||
m_tms(*this, "tms"),
|
||||
m_novram(*this, "novram12%c", 'b'),
|
||||
#if DEBUG_GFXDECODE
|
||||
m_gfxdecode(*this, "gfxdecode"),
|
||||
#endif
|
||||
m_palette(*this, "palette"),
|
||||
m_screen(*this, "screen"),
|
||||
m_mainbank(*this, "mainbank")
|
||||
{ }
|
||||
|
||||
DECLARE_CUSTOM_INPUT_MEMBER(audio_comm_stat_0c01_r);
|
||||
void jedi(machine_config &config);
|
||||
|
||||
protected:
|
||||
virtual void machine_start() override;
|
||||
virtual void machine_reset() override;
|
||||
virtual void video_start() override;
|
||||
|
||||
private:
|
||||
required_shared_ptr<u8> m_backgroundram;
|
||||
required_shared_ptr<u8> m_foregroundram;
|
||||
required_shared_ptr<u8> m_spriteram;
|
||||
required_shared_ptr<u8> m_smoothing_table;
|
||||
required_region_ptr<u8> m_tx_gfx;
|
||||
required_region_ptr<u8> m_bg_gfx;
|
||||
required_region_ptr<u8> m_spr_gfx;
|
||||
required_region_ptr<u8> m_proms;
|
||||
required_device<cpu_device> m_maincpu;
|
||||
required_device<cpu_device> m_audiocpu;
|
||||
required_device<generic_latch_8_device> m_soundlatch;
|
||||
required_device<generic_latch_8_device> m_sacklatch;
|
||||
required_device<tms5220_device> m_tms;
|
||||
required_device_array<x2212_device, 2> m_novram;
|
||||
#if DEBUG_GFXDECODE
|
||||
required_device<gfxdecode_device> m_gfxdecode;
|
||||
std::unique_ptr<u8[]> m_gfxdata;
|
||||
#endif
|
||||
required_device<palette_device> m_palette;
|
||||
required_device<screen_device> m_screen;
|
||||
required_memory_bank m_mainbank;
|
||||
|
||||
u32 m_vscroll = 0;
|
||||
u32 m_hscroll = 0;
|
||||
bool m_foreground_bank = false;
|
||||
bool m_video_off = false;
|
||||
|
||||
emu_timer *m_interrupt_timer = nullptr;
|
||||
|
||||
void main_irq_ack_w(u8 data);
|
||||
void rom_banksel_w(u8 data);
|
||||
template <uint8_t Which> DECLARE_WRITE_LINE_MEMBER(coin_counter_w);
|
||||
u8 novram_data_r(address_space &space, offs_t offset);
|
||||
void novram_data_w(offs_t offset, u8 data);
|
||||
void novram_recall_w(offs_t offset, u8 data);
|
||||
void novram_store_w(u8 data);
|
||||
void vscroll_w(offs_t offset, u8 data);
|
||||
void hscroll_w(offs_t offset, u8 data);
|
||||
void irq_ack_w(u8 data);
|
||||
DECLARE_WRITE_LINE_MEMBER(audio_reset_w);
|
||||
u8 audio_comm_stat_r();
|
||||
void speech_strobe_w(offs_t offset, u8 data);
|
||||
u8 speech_ready_r();
|
||||
void speech_reset_w(u8 data);
|
||||
DECLARE_WRITE_LINE_MEMBER(foreground_bank_w);
|
||||
DECLARE_WRITE_LINE_MEMBER(video_off_w);
|
||||
u32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
|
||||
TIMER_CALLBACK_MEMBER(generate_interrupt);
|
||||
static rgb_t jedi_IRGB_3333(u32 raw);
|
||||
void do_pen_lookup(bitmap_rgb32 &bitmap, const rectangle &cliprect);
|
||||
void draw_background_and_text(bitmap_rgb32 &bitmap, const rectangle &cliprect);
|
||||
void draw_sprites(bitmap_rgb32 &bitmap, const rectangle &cliprect);
|
||||
|
||||
void audio_map(address_map &map);
|
||||
void main_map(address_map &map);
|
||||
};
|
||||
|
||||
|
||||
// audio
|
||||
|
||||
/*************************************
|
||||
*
|
||||
* Interrupt handling
|
||||
*
|
||||
*************************************/
|
||||
|
||||
void jedi_state::irq_ack_w(u8 data)
|
||||
{
|
||||
m_audiocpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*************************************
|
||||
*
|
||||
* Main CPU -> Sound CPU communications
|
||||
*
|
||||
*************************************/
|
||||
|
||||
WRITE_LINE_MEMBER(jedi_state::audio_reset_w)
|
||||
{
|
||||
m_audiocpu->set_input_line(INPUT_LINE_RESET, state ? CLEAR_LINE : ASSERT_LINE);
|
||||
if (!state)
|
||||
m_tms->set_output_gain(ALL_OUTPUTS, 0.0);
|
||||
}
|
||||
|
||||
|
||||
u8 jedi_state::audio_comm_stat_r()
|
||||
{
|
||||
return (m_soundlatch->pending_r() << 7) | (m_sacklatch->pending_r() << 6);
|
||||
}
|
||||
|
||||
|
||||
CUSTOM_INPUT_MEMBER(jedi_state::audio_comm_stat_0c01_r)
|
||||
{
|
||||
return (m_soundlatch->pending_r() << 1) | m_sacklatch->pending_r();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*************************************
|
||||
*
|
||||
* Speech access
|
||||
*
|
||||
*************************************/
|
||||
|
||||
void jedi_state::speech_strobe_w(offs_t offset, u8 data)
|
||||
{
|
||||
m_tms->wsq_w(BIT(offset, 8));
|
||||
}
|
||||
|
||||
|
||||
u8 jedi_state::speech_ready_r()
|
||||
{
|
||||
return m_tms->readyq_r() << 7;
|
||||
}
|
||||
|
||||
|
||||
void jedi_state::speech_reset_w(u8 data)
|
||||
{
|
||||
// Flip-flop at 8C controls the power supply to the TMS5220 (through transistors Q6 and Q7)
|
||||
m_tms->set_output_gain(ALL_OUTPUTS, BIT(data, 0) ? 1.0 : 0.0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*************************************
|
||||
*
|
||||
* Audio CPU memory handlers
|
||||
*
|
||||
*************************************/
|
||||
|
||||
void jedi_state::audio_map(address_map &map)
|
||||
{
|
||||
map(0x0000, 0x07ff).ram();
|
||||
map(0x0800, 0x080f).mirror(0x07c0).rw("pokey1", FUNC(pokey_device::read), FUNC(pokey_device::write));
|
||||
map(0x0810, 0x081f).mirror(0x07c0).rw("pokey2", FUNC(pokey_device::read), FUNC(pokey_device::write));
|
||||
map(0x0820, 0x082f).mirror(0x07c0).rw("pokey3", FUNC(pokey_device::read), FUNC(pokey_device::write));
|
||||
map(0x0830, 0x083f).mirror(0x07c0).rw("pokey4", FUNC(pokey_device::read), FUNC(pokey_device::write));
|
||||
map(0x1000, 0x1000).mirror(0x00ff).nopr().w(FUNC(jedi_state::irq_ack_w));
|
||||
map(0x1100, 0x1100).mirror(0x00ff).nopr().w(m_tms, FUNC(tms5220_device::data_w));
|
||||
map(0x1200, 0x13ff).nopr().w(FUNC(jedi_state::speech_strobe_w));
|
||||
map(0x1400, 0x1400).mirror(0x00ff).nopr().w(m_sacklatch, FUNC(generic_latch_8_device::write));
|
||||
map(0x1500, 0x1500).mirror(0x00ff).nopr().w(FUNC(jedi_state::speech_reset_w));
|
||||
map(0x1600, 0x17ff).noprw();
|
||||
map(0x1800, 0x1800).mirror(0x03ff).r(m_soundlatch, FUNC(generic_latch_8_device::read)).nopw();
|
||||
map(0x1c00, 0x1c00).mirror(0x03fe).r(FUNC(jedi_state::speech_ready_r)).nopw();
|
||||
map(0x1c01, 0x1c01).mirror(0x03fe).r(FUNC(jedi_state::audio_comm_stat_r)).nopw();
|
||||
map(0x2000, 0x7fff).noprw();
|
||||
map(0x8000, 0xffff).rom();
|
||||
}
|
||||
|
||||
// video
|
||||
|
||||
/***************************************************************************
|
||||
|
||||
Return of the Jedi has a peculiar playfield/motion object
|
||||
priority system. That is, there is no priority system ;-)
|
||||
The color of the pixel which appears on screen depends on
|
||||
all three of the foreground, background and motion objects.
|
||||
The 1024 colors palette is appropriately set up by the program
|
||||
to "emulate" a priority system, but it can also be used to display
|
||||
completely different colors (see the palette test in service mode)
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
/*************************************
|
||||
*
|
||||
* Start
|
||||
*
|
||||
*************************************/
|
||||
|
||||
void jedi_state::video_start()
|
||||
{
|
||||
#if DEBUG_GFXDECODE
|
||||
// the sprite pixel determines pen address bits A4-A7
|
||||
gfx_element *gx0 = m_gfxdecode->gfx(2);
|
||||
|
||||
// allocate memory for the assembled data
|
||||
m_gfxdata = std::make_unique<u8[]>(gx0->elements() * gx0->width() * gx0->height());
|
||||
|
||||
// loop over elements
|
||||
u8 *dest = m_gfxdata.get();
|
||||
for (int c = 0; c < gx0->elements(); c++)
|
||||
{
|
||||
const u8 *c0base = gx0->get_data(c);
|
||||
|
||||
// loop over height
|
||||
for (int y = 0; y < gx0->height(); y++)
|
||||
{
|
||||
const u8 *c0 = c0base;
|
||||
|
||||
for (int x = 0; x < gx0->width(); x++)
|
||||
{
|
||||
const u8 pix = (*c0++ & 0xf);
|
||||
*dest++ = pix << 4;
|
||||
}
|
||||
c0base += gx0->rowbytes();
|
||||
}
|
||||
}
|
||||
|
||||
gx0->set_raw_layout(m_gfxdata.get(), gx0->width(), gx0->height(), gx0->elements(), 8 * gx0->width(), 8 * gx0->width() * gx0->height());
|
||||
gx0->set_granularity(1);
|
||||
#endif
|
||||
|
||||
// register for saving
|
||||
save_item(NAME(m_vscroll));
|
||||
save_item(NAME(m_hscroll));
|
||||
save_item(NAME(m_foreground_bank));
|
||||
save_item(NAME(m_video_off));
|
||||
}
|
||||
|
||||
|
||||
WRITE_LINE_MEMBER(jedi_state::foreground_bank_w)
|
||||
{
|
||||
m_foreground_bank = state;
|
||||
}
|
||||
|
||||
|
||||
WRITE_LINE_MEMBER(jedi_state::video_off_w)
|
||||
{
|
||||
m_video_off = state;
|
||||
}
|
||||
|
||||
|
||||
/*************************************
|
||||
*
|
||||
* Palette RAM
|
||||
*
|
||||
*************************************
|
||||
*
|
||||
* Color RAM format
|
||||
* Color RAM is 1024x12
|
||||
*
|
||||
* RAM address: A0..A3 = Playfield color code
|
||||
* A4..A7 = Motion object color code
|
||||
* A8..A9 = Alphanumeric color code
|
||||
*
|
||||
* RAM data:
|
||||
* 0..2 = Blue
|
||||
* 3..5 = Green
|
||||
* 6..8 = Blue
|
||||
* 9..11 = Intensity
|
||||
*
|
||||
* Output resistor values:
|
||||
* bit 0 = 22K
|
||||
* bit 1 = 10K
|
||||
* bit 2 = 4.7K
|
||||
*
|
||||
*************************************/
|
||||
|
||||
rgb_t jedi_state::jedi_IRGB_3333(u32 raw)
|
||||
{
|
||||
const u8 intensity = (raw >> 9) & 7;
|
||||
u8 bits = (raw >> 6) & 7;
|
||||
const u8 r = 5 * bits * intensity;
|
||||
bits = (raw >> 3) & 7;
|
||||
const u8 g = 5 * bits * intensity;
|
||||
bits = (raw >> 0) & 7;
|
||||
const u8 b = 5 * bits * intensity;
|
||||
|
||||
return rgb_t(r, g, b);
|
||||
}
|
||||
|
||||
void jedi_state::do_pen_lookup(bitmap_rgb32 &bitmap, const rectangle &cliprect)
|
||||
{
|
||||
for (int y = cliprect.top(); y <= cliprect.bottom(); y++)
|
||||
for(int x = cliprect.left(); x <= cliprect.right(); x++)
|
||||
bitmap.pix(y, x) = m_palette->pen(bitmap.pix(y, x));
|
||||
}
|
||||
|
||||
|
||||
/*************************************
|
||||
*
|
||||
* Scroll offsets
|
||||
*
|
||||
*************************************/
|
||||
|
||||
void jedi_state::vscroll_w(offs_t offset, u8 data)
|
||||
{
|
||||
m_vscroll = data | (offset << 8);
|
||||
}
|
||||
|
||||
|
||||
void jedi_state::hscroll_w(offs_t offset, u8 data)
|
||||
{
|
||||
m_hscroll = data | (offset << 8);
|
||||
}
|
||||
|
||||
|
||||
/*************************************
|
||||
*
|
||||
* Background/text layer drawing
|
||||
* with smoothing
|
||||
*
|
||||
*************************************/
|
||||
|
||||
void jedi_state::draw_background_and_text(bitmap_rgb32 &bitmap, const rectangle &cliprect)
|
||||
{
|
||||
u8 background_line_buffer[0x200]; // RAM chip at 2A
|
||||
|
||||
const u8 *prom1 = &m_proms[0x0000 | ((*m_smoothing_table & 0x03) << 8)];
|
||||
const u8 *prom2 = &m_proms[0x0800 | ((*m_smoothing_table & 0x03) << 8)];
|
||||
|
||||
std::fill(std::begin(background_line_buffer), std::end(background_line_buffer), 0);
|
||||
|
||||
for (int y = cliprect.top(); y <= cliprect.bottom(); y++)
|
||||
{
|
||||
u8 bg_last_col = 0;
|
||||
|
||||
for (int x = cliprect.left(); x <= cliprect.right(); x += 2)
|
||||
{
|
||||
u16 tx_col1, tx_col2, bg_col = 0;
|
||||
|
||||
const int sy = y + m_vscroll;
|
||||
int sx = x + m_hscroll;
|
||||
|
||||
// determine offsets into video memory
|
||||
const offs_t tx_offs = ((y & 0xf8) << 3) | (x >> 3);
|
||||
const offs_t bg_offs = ((sy & 0x1f0) << 1) | ((sx & 0x1f0) >> 4);
|
||||
|
||||
// get the character codes
|
||||
const int tx_code = (m_foreground_bank << 8) | m_foregroundram[tx_offs];
|
||||
const int bg_bank = m_backgroundram[0x0400 | bg_offs];
|
||||
const int bg_code = m_backgroundram[0x0000 | bg_offs] |
|
||||
((bg_bank & 0x01) << 8) |
|
||||
((bg_bank & 0x08) << 6) |
|
||||
((bg_bank & 0x02) << 9);
|
||||
|
||||
// background flip X
|
||||
if (bg_bank & 0x04)
|
||||
sx = sx ^ 0x0f;
|
||||
|
||||
// calculate the address of the gfx data
|
||||
const offs_t tx_gfx_offs = (tx_code << 4) | ((y & 0x07) << 1) | ((( x & 0x04) >> 2));
|
||||
const offs_t bg_gfx_offs = (bg_code << 4) | (sy & 0x0e) | (((sx & 0x08) >> 3));
|
||||
|
||||
// get the gfx data
|
||||
const u8 tx_data = m_tx_gfx[ tx_gfx_offs];
|
||||
const u8 bg_data1 = m_bg_gfx[0x0000 | bg_gfx_offs];
|
||||
const u8 bg_data2 = m_bg_gfx[0x8000 | bg_gfx_offs];
|
||||
|
||||
// the text layer pixel determines pen address bits A8 and A9
|
||||
if (x & 0x02)
|
||||
{
|
||||
tx_col1 = ((tx_data & 0x0c) << 6);
|
||||
tx_col2 = ((tx_data & 0x03) << 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
tx_col1 = ((tx_data & 0xc0) << 2);
|
||||
tx_col2 = ((tx_data & 0x30) << 4);
|
||||
}
|
||||
|
||||
// the background pixel determines pen address bits A0-A3
|
||||
switch (sx & 0x06)
|
||||
{
|
||||
case 0x00: bg_col = ((bg_data1 & 0x80) >> 4) | ((bg_data1 & 0x08) >> 1) | ((bg_data2 & 0x80) >> 6) | ((bg_data2 & 0x08) >> 3); break;
|
||||
case 0x02: bg_col = ((bg_data1 & 0x40) >> 3) | ((bg_data1 & 0x04) >> 0) | ((bg_data2 & 0x40) >> 5) | ((bg_data2 & 0x04) >> 2); break;
|
||||
case 0x04: bg_col = ((bg_data1 & 0x20) >> 2) | ((bg_data1 & 0x02) << 1) | ((bg_data2 & 0x20) >> 4) | ((bg_data2 & 0x02) >> 1); break;
|
||||
case 0x06: bg_col = ((bg_data1 & 0x10) >> 1) | ((bg_data1 & 0x01) << 2) | ((bg_data2 & 0x10) >> 3) | ((bg_data2 & 0x01) >> 0); break;
|
||||
}
|
||||
|
||||
/* the first pixel is smoothed via a lookup using the current and last pixel value -
|
||||
the next pixel just uses the current value directly. After we done with a pixel
|
||||
save it for later in the line buffer RAM */
|
||||
const u8 bg_tempcol = prom1[(bg_last_col << 4) | bg_col];
|
||||
bitmap.pix(y, x + 0) = tx_col1 | prom2[(background_line_buffer[x + 0] << 4) | bg_tempcol];
|
||||
bitmap.pix(y, x + 1) = tx_col2 | prom2[(background_line_buffer[x + 1] << 4) | bg_col];
|
||||
background_line_buffer[x + 0] = bg_tempcol;
|
||||
background_line_buffer[x + 1] = bg_col;
|
||||
|
||||
bg_last_col = bg_col;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*************************************
|
||||
*
|
||||
* Sprite drawing
|
||||
*
|
||||
*************************************/
|
||||
|
||||
void jedi_state::draw_sprites(bitmap_rgb32 &bitmap, const rectangle &cliprect)
|
||||
{
|
||||
for (offs_t offs = 0x00; offs < 0x30; offs++)
|
||||
{
|
||||
int y_size;
|
||||
|
||||
// coordinates adjustments made to match screenshot
|
||||
u8 y = 240 - m_spriteram[offs + 0x80] + 1;
|
||||
const bool flip_x = m_spriteram[offs + 0x40] & 0x10;
|
||||
const bool flip_y = m_spriteram[offs + 0x40] & 0x20;
|
||||
const bool tall = m_spriteram[offs + 0x40] & 0x08;
|
||||
|
||||
// shuffle the bank bits in
|
||||
u16 code = m_spriteram[offs] |
|
||||
((m_spriteram[offs + 0x40] & 0x04) << 8) |
|
||||
((m_spriteram[offs + 0x40] & 0x40) << 3) |
|
||||
((m_spriteram[offs + 0x40] & 0x02) << 7);
|
||||
|
||||
// adjust for double-height
|
||||
if (tall)
|
||||
{
|
||||
code &= ~1;
|
||||
y_size = 0x20;
|
||||
y = y - 0x10;
|
||||
}
|
||||
else
|
||||
y_size = 0x10;
|
||||
|
||||
const u8 *gfx = &m_spr_gfx[code << 5];
|
||||
|
||||
if (flip_y)
|
||||
y = y + y_size - 1;
|
||||
|
||||
for (int sy = 0; sy < y_size; sy++)
|
||||
{
|
||||
u16 x = m_spriteram[offs + 0x100] + ((m_spriteram[offs + 0x40] & 0x01) << 8) - 2;
|
||||
|
||||
if (flip_x)
|
||||
x = x + 7;
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
u8 data1 = *(0x00000 + gfx);
|
||||
u8 data2 = *(0x10000 + gfx);
|
||||
|
||||
for (int sx = 0; sx < 4; sx++)
|
||||
{
|
||||
// the sprite pixel determines pen address bits A4-A7
|
||||
const u32 col = ((data1 & 0x80) >> 0) | ((data1 & 0x08) << 3) | ((data2 & 0x80) >> 2) | ((data2 & 0x08) << 1);
|
||||
|
||||
x = x & 0x1ff;
|
||||
|
||||
if (col && cliprect.contains(x, y))
|
||||
bitmap.pix(y, x) = (bitmap.pix(y, x) & 0x30f) | col;
|
||||
|
||||
// next pixel
|
||||
if (flip_x)
|
||||
x = x - 1;
|
||||
else
|
||||
x = x + 1;
|
||||
|
||||
data1 = data1 << 1;
|
||||
data2 = data2 << 1;
|
||||
}
|
||||
|
||||
gfx = gfx + 1;
|
||||
}
|
||||
|
||||
if (flip_y)
|
||||
y = y - 1;
|
||||
else
|
||||
y = y + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*************************************
|
||||
*
|
||||
* Core video refresh
|
||||
*
|
||||
*************************************/
|
||||
|
||||
u32 jedi_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
|
||||
{
|
||||
// if no video, clear it all to black
|
||||
if (m_video_off)
|
||||
bitmap.fill(rgb_t::black(), cliprect);
|
||||
else
|
||||
{
|
||||
// draw the background/text layers, followed by the sprites - it needs to be done in this order
|
||||
draw_background_and_text(bitmap, cliprect);
|
||||
draw_sprites(bitmap, cliprect);
|
||||
do_pen_lookup(bitmap, cliprect);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*************************************
|
||||
*
|
||||
* Machine driver
|
||||
*
|
||||
*************************************/
|
||||
|
||||
#if DEBUG_GFXDECODE
|
||||
static const gfx_layout text_layout =
|
||||
{
|
||||
8, 8,
|
||||
RGN_FRAC(1,1),
|
||||
2,
|
||||
{ 0, 1 },
|
||||
{ STEP8(0, 2) },
|
||||
{ STEP8(0, 2*8) },
|
||||
8*8*2
|
||||
};
|
||||
|
||||
static const gfx_layout bg_layout =
|
||||
{
|
||||
8, 8,
|
||||
RGN_FRAC(1,2),
|
||||
4,
|
||||
{ 0, 4, RGN_FRAC(1,2)+0, RGN_FRAC(1,2)+4 },
|
||||
{ STEP4(0, 1), STEP4(4*2, 1) },
|
||||
{ STEP8(0, 4*2*2) },
|
||||
8*8*2
|
||||
};
|
||||
|
||||
static const gfx_layout sprite_layout =
|
||||
{
|
||||
8, 16,
|
||||
RGN_FRAC(1,2),
|
||||
4,
|
||||
{ 0, 4, RGN_FRAC(1,2)+0, RGN_FRAC(1,2)+4 },
|
||||
{ STEP4(0, 1), STEP4(4*2, 1) },
|
||||
{ STEP16(0, 4*2*2) },
|
||||
8*16*2
|
||||
};
|
||||
|
||||
static GFXDECODE_START( gfx_jedi )
|
||||
GFXDECODE_ENTRY( "tx_gfx", 0, text_layout, 0, 0x400/0x04 )
|
||||
GFXDECODE_SCALE( "bg_gfx", 0, bg_layout, 0, 0x400/0x10, 2, 2 ) // 8x8 but internally expanded related with smoothing
|
||||
GFXDECODE_ENTRY( "spr_gfx", 0, sprite_layout, 0, 0x310 )
|
||||
GFXDECODE_END
|
||||
#endif
|
||||
|
||||
|
||||
// machine
|
||||
|
||||
/*************************************
|
||||
*
|
||||
@ -131,11 +717,11 @@ TIMER_CALLBACK_MEMBER(jedi_state::generate_interrupt)
|
||||
{
|
||||
int scanline = param;
|
||||
|
||||
/* IRQ is set by /32V */
|
||||
// IRQ is set by /32V
|
||||
m_maincpu->set_input_line(M6502_IRQ_LINE, (scanline & 32) ? CLEAR_LINE : ASSERT_LINE);
|
||||
m_audiocpu->set_input_line(M6502_IRQ_LINE, (scanline & 32) ? CLEAR_LINE : ASSERT_LINE);
|
||||
|
||||
/* set up for the next */
|
||||
// set up for the next
|
||||
scanline += 32;
|
||||
if (scanline > 256)
|
||||
scanline = 32;
|
||||
@ -157,11 +743,11 @@ void jedi_state::main_irq_ack_w(u8 data)
|
||||
|
||||
void jedi_state::machine_start()
|
||||
{
|
||||
/* set a timer to run the interrupts */
|
||||
// set a timer to run the interrupts
|
||||
m_interrupt_timer = timer_alloc(FUNC(jedi_state::generate_interrupt), this);
|
||||
m_interrupt_timer->adjust(m_screen->time_until_pos(32), 32);
|
||||
|
||||
/* configure the banks */
|
||||
// configure the banks
|
||||
m_mainbank->configure_entries(0, 3, memregion("maincpu")->base() + 0x10000, 0x4000);
|
||||
}
|
||||
|
||||
@ -199,15 +785,10 @@ void jedi_state::rom_banksel_w(u8 data)
|
||||
*
|
||||
*************************************/
|
||||
|
||||
WRITE_LINE_MEMBER(jedi_state::coin_counter_left_w)
|
||||
template <uint8_t Which> // 0 left, 1 right
|
||||
WRITE_LINE_MEMBER(jedi_state::coin_counter_w)
|
||||
{
|
||||
machine().bookkeeping().coin_counter_w(0, state);
|
||||
}
|
||||
|
||||
|
||||
WRITE_LINE_MEMBER(jedi_state::coin_counter_right_w)
|
||||
{
|
||||
machine().bookkeeping().coin_counter_w(1, state);
|
||||
machine().bookkeeping().coin_counter_w(Which, state);
|
||||
}
|
||||
|
||||
|
||||
@ -267,17 +848,17 @@ void jedi_state::main_map(address_map &map)
|
||||
map(0x1d80, 0x1d80).mirror(0x007f).nopr().w("watchdog", FUNC(watchdog_timer_device::reset_w));
|
||||
map(0x1e00, 0x1e00).mirror(0x007f).nopr().w(FUNC(jedi_state::main_irq_ack_w));
|
||||
map(0x1e80, 0x1e87).mirror(0x0078).nopr().w("outlatch", FUNC(ls259_device::write_d7));
|
||||
map(0x1f00, 0x1f00).mirror(0x007f).nopr().w("soundlatch", FUNC(generic_latch_8_device::write));
|
||||
map(0x1f00, 0x1f00).mirror(0x007f).nopr().w(m_soundlatch, FUNC(generic_latch_8_device::write));
|
||||
map(0x1f80, 0x1f80).mirror(0x007f).nopr().w(FUNC(jedi_state::rom_banksel_w));
|
||||
map(0x2000, 0x27ff).ram().share("backgroundram");
|
||||
map(0x2000, 0x27ff).ram().share(m_backgroundram);
|
||||
map(0x2800, 0x2bff).ram().w(m_palette, FUNC(palette_device::write8)).share("palette");
|
||||
map(0x2c00, 0x2fff).ram().w(m_palette, FUNC(palette_device::write8_ext)).share("palette_ext");
|
||||
map(0x3000, 0x37bf).ram().share("foregroundram");
|
||||
map(0x37c0, 0x3bff).ram().share("spriteram");
|
||||
map(0x3000, 0x37bf).ram().share(m_foregroundram);
|
||||
map(0x37c0, 0x3bff).ram().share(m_spriteram);
|
||||
map(0x3c00, 0x3c01).mirror(0x00fe).nopr().w(FUNC(jedi_state::vscroll_w));
|
||||
map(0x3d00, 0x3d01).mirror(0x00fe).nopr().w(FUNC(jedi_state::hscroll_w));
|
||||
map(0x3e00, 0x3e00).mirror(0x01ff).writeonly().share("smoothing_table");
|
||||
map(0x4000, 0x7fff).bankr("mainbank");
|
||||
map(0x4000, 0x7fff).bankr(m_mainbank);
|
||||
map(0x8000, 0xffff).rom();
|
||||
}
|
||||
|
||||
@ -303,7 +884,7 @@ static INPUT_PORTS_START( jedi )
|
||||
PORT_BIT( 0x03, IP_ACTIVE_LOW, IPT_UNUSED )
|
||||
PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_TILT )
|
||||
PORT_BIT( 0x18, IP_ACTIVE_LOW, IPT_UNUSED )
|
||||
PORT_BIT( 0x60, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_CUSTOM_MEMBER(jedi_state, jedi_audio_comm_stat_r)
|
||||
PORT_BIT( 0x60, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_CUSTOM_MEMBER(jedi_state, audio_comm_stat_0c01_r)
|
||||
PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_VBLANK("screen")
|
||||
|
||||
PORT_START("STICKY")
|
||||
@ -322,7 +903,14 @@ INPUT_PORTS_END
|
||||
|
||||
void jedi_state::jedi(machine_config &config)
|
||||
{
|
||||
/* basic machine hardware */
|
||||
constexpr XTAL JEDI_MAIN_CPU_OSC = XTAL(10'000'000);
|
||||
constexpr XTAL JEDI_AUDIO_CPU_OSC = XTAL(12'096'000);
|
||||
constexpr XTAL JEDI_MAIN_CPU_CLOCK = JEDI_MAIN_CPU_OSC / 4;
|
||||
constexpr XTAL JEDI_AUDIO_CPU_CLOCK = JEDI_AUDIO_CPU_OSC / 8;
|
||||
constexpr XTAL JEDI_POKEY_CLOCK = JEDI_AUDIO_CPU_CLOCK;
|
||||
constexpr XTAL JEDI_TMS5220_CLOCK = JEDI_AUDIO_CPU_OSC / 2 / 9; // div by 9 is via a binary counter that counts from 7 to 16
|
||||
|
||||
// basic machine hardware
|
||||
M6502(config, m_maincpu, JEDI_MAIN_CPU_CLOCK);
|
||||
m_maincpu->set_addrmap(AS_PROGRAM, &jedi_state::main_map);
|
||||
|
||||
@ -338,8 +926,8 @@ void jedi_state::jedi(machine_config &config)
|
||||
adc.in_callback<3>().set_constant(0); // SPARE
|
||||
|
||||
ls259_device &outlatch(LS259(config, "outlatch")); // 14J
|
||||
outlatch.q_out_cb<0>().set(FUNC(jedi_state::coin_counter_left_w));
|
||||
outlatch.q_out_cb<1>().set(FUNC(jedi_state::coin_counter_right_w));
|
||||
outlatch.q_out_cb<0>().set(FUNC(jedi_state::coin_counter_w<0>));
|
||||
outlatch.q_out_cb<1>().set(FUNC(jedi_state::coin_counter_w<1>));
|
||||
outlatch.q_out_cb<2>().set_nop(); // LED control - not used
|
||||
outlatch.q_out_cb<3>().set_nop(); // LED control - not used
|
||||
outlatch.q_out_cb<4>().set(FUNC(jedi_state::foreground_bank_w));
|
||||
@ -348,11 +936,49 @@ void jedi_state::jedi(machine_config &config)
|
||||
|
||||
WATCHDOG_TIMER(config, "watchdog");
|
||||
|
||||
/* video hardware */
|
||||
jedi_video(config);
|
||||
// video hardware
|
||||
#if DEBUG_GFXDECODE
|
||||
GFXDECODE(config, m_gfxdecode, m_palette, gfx_jedi);
|
||||
#endif
|
||||
SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
|
||||
m_screen->set_refresh_hz(60);
|
||||
m_screen->set_size(64*8, 262); // verify vert size
|
||||
m_screen->set_visarea(0*8, 37*8-1, 0*8, 30*8-1);
|
||||
m_screen->set_screen_update(FUNC(jedi_state::screen_update));
|
||||
|
||||
/* audio hardware */
|
||||
jedi_audio(config);
|
||||
PALETTE(config, m_palette).set_format(2, &jedi_state::jedi_IRGB_3333, 0x400);
|
||||
|
||||
// audio hardware
|
||||
M6502(config, m_audiocpu, JEDI_AUDIO_CPU_CLOCK);
|
||||
m_audiocpu->set_addrmap(AS_PROGRAM, &jedi_state::audio_map);
|
||||
|
||||
SPEAKER(config, "lspeaker").front_left();
|
||||
SPEAKER(config, "rspeaker").front_right();
|
||||
|
||||
pokey_device &pokey1(POKEY(config, "pokey1", JEDI_POKEY_CLOCK));
|
||||
pokey1.set_output_opamp(RES_K(1), 0.0, 5.0);
|
||||
pokey1.add_route(ALL_OUTPUTS, "lspeaker", 0.30);
|
||||
pokey1.add_route(ALL_OUTPUTS, "rspeaker", 0.30);
|
||||
|
||||
pokey_device &pokey2(POKEY(config, "pokey2", JEDI_POKEY_CLOCK));
|
||||
pokey2.set_output_opamp(RES_K(1), 0.0, 5.0);
|
||||
pokey2.add_route(ALL_OUTPUTS, "lspeaker", 0.30);
|
||||
pokey2.add_route(ALL_OUTPUTS, "rspeaker", 0.30);
|
||||
|
||||
pokey_device &pokey3(POKEY(config, "pokey3", JEDI_POKEY_CLOCK));
|
||||
pokey3.set_output_opamp(RES_K(1), 0.0, 5.0);
|
||||
pokey3.add_route(ALL_OUTPUTS, "lspeaker", 0.30);
|
||||
|
||||
pokey_device &pokey4(POKEY(config, "pokey4", JEDI_POKEY_CLOCK));
|
||||
pokey4.set_output_opamp(RES_K(1), 0.0, 5.0);
|
||||
pokey4.add_route(ALL_OUTPUTS, "rspeaker", 0.30);
|
||||
|
||||
TMS5220(config, m_tms, JEDI_TMS5220_CLOCK);
|
||||
m_tms->add_route(ALL_OUTPUTS, "lspeaker", 1.0);
|
||||
m_tms->add_route(ALL_OUTPUTS, "rspeaker", 1.0);
|
||||
|
||||
GENERIC_LATCH_8(config, m_soundlatch); // 5E (LS374) + 3E (LS279) pins 13-15
|
||||
GENERIC_LATCH_8(config, m_sacklatch); // 4E (LS374) + 3E (LS279) pins 1-4
|
||||
}
|
||||
|
||||
|
||||
@ -363,31 +989,31 @@ void jedi_state::jedi(machine_config &config)
|
||||
*************************************/
|
||||
|
||||
ROM_START( jedi )
|
||||
ROM_REGION( 0x1C000, "maincpu", 0 ) /* 64k for code + 48k for banked ROMs */
|
||||
ROM_REGION( 0x1C000, "maincpu", 0 )
|
||||
ROM_LOAD( "136030-221.14f", 0x08000, 0x4000, CRC(414d05e3) SHA1(e5f5f8d85433467a13d6ca9e3889e07a62b00e52) )
|
||||
ROM_LOAD( "136030-222.13f", 0x0c000, 0x4000, CRC(7b3f21be) SHA1(8fe62401f9b78c7a3e62b544c4b705b1bfa9b8f3) )
|
||||
ROM_LOAD( "136030-123.13d", 0x10000, 0x4000, CRC(877f554a) SHA1(8b51109cabd84741b024052f892b3172fbe83223) ) /* Page 0 */
|
||||
ROM_LOAD( "136030-124.13b", 0x14000, 0x4000, CRC(e72d41db) SHA1(1b3fcdc435f1e470e8d5b7241856e398a4c3910e) ) /* Page 1 */
|
||||
ROM_LOAD( "136030-122.13a", 0x18000, 0x4000, CRC(cce7ced5) SHA1(bff031a637aefca713355dbf251dcb5c2cea0885) ) /* Page 2 */
|
||||
ROM_LOAD( "136030-123.13d", 0x10000, 0x4000, CRC(877f554a) SHA1(8b51109cabd84741b024052f892b3172fbe83223) ) // Page 0
|
||||
ROM_LOAD( "136030-124.13b", 0x14000, 0x4000, CRC(e72d41db) SHA1(1b3fcdc435f1e470e8d5b7241856e398a4c3910e) ) // Page 1
|
||||
ROM_LOAD( "136030-122.13a", 0x18000, 0x4000, CRC(cce7ced5) SHA1(bff031a637aefca713355dbf251dcb5c2cea0885) ) // Page 2
|
||||
|
||||
ROM_REGION( 0x10000, "audiocpu", 0 ) /* space for the sound ROMs */
|
||||
ROM_REGION( 0x10000, "audiocpu", 0 )
|
||||
ROM_LOAD( "136030-133.01c", 0x8000, 0x4000, CRC(6c601c69) SHA1(618b77800bbbb4db34a53ca974a71bdaf89b5930) )
|
||||
ROM_LOAD( "136030-134.01a", 0xC000, 0x4000, CRC(5e36c564) SHA1(4b0afceb9a1d912f1d5c1f26928d244d5b14ea4a) )
|
||||
|
||||
ROM_REGION( 0x02000, "tx_gfx",0 )
|
||||
ROM_LOAD( "136030-215.11t", 0x00000, 0x2000, CRC(3e49491f) SHA1(ade5e846069c2fa6edf667469d13ce5a6a45c06d) ) /* Alphanumeric */
|
||||
ROM_LOAD( "136030-215.11t", 0x00000, 0x2000, CRC(3e49491f) SHA1(ade5e846069c2fa6edf667469d13ce5a6a45c06d) )
|
||||
|
||||
ROM_REGION( 0x10000, "bg_gfx",0 )
|
||||
ROM_LOAD( "136030-126.06r", 0x00000, 0x8000, CRC(9c55ece8) SHA1(b8faa23314bb0d199ef46199bfabd9cb17510dd3) ) /* Playfield */
|
||||
ROM_LOAD( "136030-126.06r", 0x00000, 0x8000, CRC(9c55ece8) SHA1(b8faa23314bb0d199ef46199bfabd9cb17510dd3) )
|
||||
ROM_LOAD( "136030-127.06n", 0x08000, 0x8000, CRC(4b09dcc5) SHA1(d46b5f4fb69c4b8d823dd9c4d92f8713badfa44a) )
|
||||
|
||||
ROM_REGION( 0x20000, "spr_gfx", 0 )
|
||||
ROM_LOAD( "136030-130.01h", 0x00000, 0x8000, CRC(2646a793) SHA1(dcb5fd50eafbb27565bce099a884be83a9d82285) ) /* Sprites */
|
||||
ROM_LOAD( "136030-130.01h", 0x00000, 0x8000, CRC(2646a793) SHA1(dcb5fd50eafbb27565bce099a884be83a9d82285) )
|
||||
ROM_LOAD( "136030-131.01f", 0x08000, 0x8000, CRC(60107350) SHA1(ded03a46996d3f2349df7f59fd435a7ad6ed465e) )
|
||||
ROM_LOAD( "136030-128.01m", 0x10000, 0x8000, CRC(24663184) SHA1(5eba142ed926671ee131430944e59f21a55a5c57) )
|
||||
ROM_LOAD( "136030-129.01k", 0x18000, 0x8000, CRC(ac86b98c) SHA1(9f86c8801a7293fa46e9432f1651dd85bf00f4b9) )
|
||||
|
||||
ROM_REGION( 0x1000, "proms", 0 ) /* background smoothing */
|
||||
ROM_REGION( 0x1000, "proms", 0 ) // background smoothing
|
||||
ROM_LOAD( "136030-117.bin", 0x0000, 0x0400, CRC(9831bd55) SHA1(12945ef2d1582914125b9ee591567034d71d6573) )
|
||||
ROM_LOAD( "136030-118.bin", 0x0800, 0x0400, CRC(261fbfe7) SHA1(efc65a74a3718563a07b718e34d8a7aa23339a69) )
|
||||
|
||||
@ -400,6 +1026,8 @@ ROM_START( jedi )
|
||||
ROM_FILL( 0x50, 0x010, 0x00 )
|
||||
ROM_END
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
/*************************************
|
||||
*
|
||||
|
@ -1,127 +0,0 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Dan Boris, Aaron Giles
|
||||
/*************************************************************************
|
||||
|
||||
Atari Return of the Jedi hardware
|
||||
|
||||
*************************************************************************/
|
||||
#ifndef MAME_ATARI_JEDI_H
|
||||
#define MAME_ATARI_JEDI_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "machine/gen_latch.h"
|
||||
#include "machine/x2212.h"
|
||||
#include "sound/tms5220.h"
|
||||
#include "emupal.h"
|
||||
#include "screen.h"
|
||||
|
||||
#define DEBUG_GFXDECODE 0 // GFX layout for debug
|
||||
|
||||
/* oscillators and clocks */
|
||||
#define JEDI_MAIN_CPU_OSC (XTAL(10'000'000))
|
||||
#define JEDI_AUDIO_CPU_OSC (XTAL(12'096'000))
|
||||
#define JEDI_MAIN_CPU_CLOCK (JEDI_MAIN_CPU_OSC / 4)
|
||||
#define JEDI_AUDIO_CPU_CLOCK (JEDI_AUDIO_CPU_OSC / 8)
|
||||
#define JEDI_POKEY_CLOCK (JEDI_AUDIO_CPU_CLOCK)
|
||||
#define JEDI_TMS5220_CLOCK (JEDI_AUDIO_CPU_OSC / 2 / 9) /* div by 9 is via a binary counter that counts from 7 to 16 */
|
||||
|
||||
|
||||
class jedi_state : public driver_device
|
||||
{
|
||||
public:
|
||||
jedi_state(const machine_config &mconfig, device_type type, const char *tag) :
|
||||
driver_device(mconfig, type, tag),
|
||||
m_backgroundram(*this, "backgroundram"),
|
||||
m_foregroundram(*this, "foregroundram"),
|
||||
m_spriteram(*this, "spriteram"),
|
||||
m_smoothing_table(*this, "smoothing_table"),
|
||||
m_tx_gfx(*this, "tx_gfx"),
|
||||
m_bg_gfx(*this, "bg_gfx"),
|
||||
m_spr_gfx(*this, "spr_gfx"),
|
||||
m_proms(*this, "proms"),
|
||||
m_maincpu(*this, "maincpu"),
|
||||
m_audiocpu(*this, "audiocpu"),
|
||||
m_soundlatch(*this, "soundlatch"),
|
||||
m_sacklatch(*this, "sacklatch"),
|
||||
m_tms(*this, "tms"),
|
||||
m_novram(*this, "novram12%c", 'b'),
|
||||
#if DEBUG_GFXDECODE
|
||||
m_gfxdecode(*this, "gfxdecode"),
|
||||
#endif
|
||||
m_palette(*this, "palette"),
|
||||
m_screen(*this, "screen"),
|
||||
m_mainbank(*this, "mainbank")
|
||||
{ }
|
||||
|
||||
DECLARE_CUSTOM_INPUT_MEMBER(jedi_audio_comm_stat_r);
|
||||
void jedi(machine_config &config);
|
||||
|
||||
protected:
|
||||
virtual void machine_start() override;
|
||||
virtual void machine_reset() override;
|
||||
virtual void video_start() override;
|
||||
|
||||
private:
|
||||
void main_irq_ack_w(u8 data);
|
||||
void rom_banksel_w(u8 data);
|
||||
DECLARE_WRITE_LINE_MEMBER(coin_counter_left_w);
|
||||
DECLARE_WRITE_LINE_MEMBER(coin_counter_right_w);
|
||||
u8 novram_data_r(address_space &space, offs_t offset);
|
||||
void novram_data_w(offs_t offset, u8 data);
|
||||
void novram_recall_w(offs_t offset, u8 data);
|
||||
void novram_store_w(u8 data);
|
||||
void vscroll_w(offs_t offset, u8 data);
|
||||
void hscroll_w(offs_t offset, u8 data);
|
||||
void irq_ack_w(u8 data);
|
||||
DECLARE_WRITE_LINE_MEMBER(audio_reset_w);
|
||||
u8 audio_comm_stat_r();
|
||||
void speech_strobe_w(offs_t offset, u8 data);
|
||||
u8 speech_ready_r();
|
||||
void speech_reset_w(u8 data);
|
||||
DECLARE_WRITE_LINE_MEMBER(foreground_bank_w);
|
||||
DECLARE_WRITE_LINE_MEMBER(video_off_w);
|
||||
u32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
|
||||
TIMER_CALLBACK_MEMBER(generate_interrupt);
|
||||
static rgb_t jedi_IRGB_3333(u32 raw);
|
||||
void do_pen_lookup(bitmap_rgb32 &bitmap, const rectangle &cliprect);
|
||||
void draw_background_and_text(bitmap_rgb32 &bitmap, const rectangle &cliprect);
|
||||
void draw_sprites(bitmap_rgb32 &bitmap, const rectangle &cliprect);
|
||||
void jedi_audio(machine_config &config);
|
||||
void jedi_video(machine_config &config);
|
||||
void audio_map(address_map &map);
|
||||
void main_map(address_map &map);
|
||||
|
||||
/* machine state */
|
||||
emu_timer *m_interrupt_timer = nullptr;
|
||||
|
||||
/* video state */
|
||||
required_shared_ptr<u8> m_backgroundram;
|
||||
required_shared_ptr<u8> m_foregroundram;
|
||||
required_shared_ptr<u8> m_spriteram;
|
||||
required_shared_ptr<u8> m_smoothing_table;
|
||||
required_region_ptr<u8> m_tx_gfx;
|
||||
required_region_ptr<u8> m_bg_gfx;
|
||||
required_region_ptr<u8> m_spr_gfx;
|
||||
required_region_ptr<u8> m_proms;
|
||||
u32 m_vscroll = 0;
|
||||
u32 m_hscroll = 0;
|
||||
bool m_foreground_bank = false;
|
||||
bool m_video_off = false;
|
||||
|
||||
required_device<cpu_device> m_maincpu;
|
||||
required_device<cpu_device> m_audiocpu;
|
||||
required_device<generic_latch_8_device> m_soundlatch;
|
||||
required_device<generic_latch_8_device> m_sacklatch;
|
||||
required_device<tms5220_device> m_tms;
|
||||
required_device_array<x2212_device, 2> m_novram;
|
||||
#if DEBUG_GFXDECODE
|
||||
required_device<gfxdecode_device> m_gfxdecode;
|
||||
std::unique_ptr<u8[]> m_gfxdata;
|
||||
#endif
|
||||
required_device<palette_device> m_palette;
|
||||
required_device<screen_device> m_screen;
|
||||
required_memory_bank m_mainbank;
|
||||
};
|
||||
|
||||
#endif // MAME_ATARI_JEDI_H
|
@ -1,152 +0,0 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Dan Boris
|
||||
/***************************************************************************
|
||||
|
||||
Atari Return of the Jedi hardware
|
||||
|
||||
driver by Dan Boris
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "jedi.h"
|
||||
#include "cpu/m6502/m6502.h"
|
||||
#include "machine/rescap.h"
|
||||
#include "sound/pokey.h"
|
||||
#include "speaker.h"
|
||||
|
||||
|
||||
|
||||
/*************************************
|
||||
*
|
||||
* Interrupt handling
|
||||
*
|
||||
*************************************/
|
||||
|
||||
void jedi_state::irq_ack_w(u8 data)
|
||||
{
|
||||
m_audiocpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*************************************
|
||||
*
|
||||
* Main CPU -> Sound CPU communications
|
||||
*
|
||||
*************************************/
|
||||
|
||||
WRITE_LINE_MEMBER(jedi_state::audio_reset_w)
|
||||
{
|
||||
m_audiocpu->set_input_line(INPUT_LINE_RESET, state ? CLEAR_LINE : ASSERT_LINE);
|
||||
if (!state)
|
||||
m_tms->set_output_gain(ALL_OUTPUTS, 0.0);
|
||||
}
|
||||
|
||||
|
||||
u8 jedi_state::audio_comm_stat_r()
|
||||
{
|
||||
return (m_soundlatch->pending_r() << 7) | (m_sacklatch->pending_r() << 6);
|
||||
}
|
||||
|
||||
|
||||
CUSTOM_INPUT_MEMBER(jedi_state::jedi_audio_comm_stat_r)
|
||||
{
|
||||
return (m_soundlatch->pending_r() << 1) | m_sacklatch->pending_r();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*************************************
|
||||
*
|
||||
* Speech access
|
||||
*
|
||||
*************************************/
|
||||
|
||||
void jedi_state::speech_strobe_w(offs_t offset, u8 data)
|
||||
{
|
||||
m_tms->wsq_w(BIT(offset, 8));
|
||||
}
|
||||
|
||||
|
||||
u8 jedi_state::speech_ready_r()
|
||||
{
|
||||
return m_tms->readyq_r() << 7;
|
||||
}
|
||||
|
||||
|
||||
void jedi_state::speech_reset_w(u8 data)
|
||||
{
|
||||
// Flip-flop at 8C controls the power supply to the TMS5220 (through transistors Q6 and Q7)
|
||||
m_tms->set_output_gain(ALL_OUTPUTS, BIT(data, 0) ? 1.0 : 0.0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*************************************
|
||||
*
|
||||
* Audio CPU memory handlers
|
||||
*
|
||||
*************************************/
|
||||
|
||||
void jedi_state::audio_map(address_map &map)
|
||||
{
|
||||
map(0x0000, 0x07ff).ram();
|
||||
map(0x0800, 0x080f).mirror(0x07c0).rw("pokey1", FUNC(pokey_device::read), FUNC(pokey_device::write));
|
||||
map(0x0810, 0x081f).mirror(0x07c0).rw("pokey2", FUNC(pokey_device::read), FUNC(pokey_device::write));
|
||||
map(0x0820, 0x082f).mirror(0x07c0).rw("pokey3", FUNC(pokey_device::read), FUNC(pokey_device::write));
|
||||
map(0x0830, 0x083f).mirror(0x07c0).rw("pokey4", FUNC(pokey_device::read), FUNC(pokey_device::write));
|
||||
map(0x1000, 0x1000).mirror(0x00ff).nopr().w(FUNC(jedi_state::irq_ack_w));
|
||||
map(0x1100, 0x1100).mirror(0x00ff).nopr().w("tms", FUNC(tms5220_device::data_w));
|
||||
map(0x1200, 0x13ff).nopr().w(FUNC(jedi_state::speech_strobe_w));
|
||||
map(0x1400, 0x1400).mirror(0x00ff).nopr().w("sacklatch", FUNC(generic_latch_8_device::write));
|
||||
map(0x1500, 0x1500).mirror(0x00ff).nopr().w(FUNC(jedi_state::speech_reset_w));
|
||||
map(0x1600, 0x17ff).noprw();
|
||||
map(0x1800, 0x1800).mirror(0x03ff).r("soundlatch", FUNC(generic_latch_8_device::read)).nopw();
|
||||
map(0x1c00, 0x1c00).mirror(0x03fe).r(FUNC(jedi_state::speech_ready_r)).nopw();
|
||||
map(0x1c01, 0x1c01).mirror(0x03fe).r(FUNC(jedi_state::audio_comm_stat_r)).nopw();
|
||||
map(0x2000, 0x7fff).noprw();
|
||||
map(0x8000, 0xffff).rom();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*************************************
|
||||
*
|
||||
* Machine driver
|
||||
*
|
||||
*************************************/
|
||||
|
||||
void jedi_state::jedi_audio(machine_config &config)
|
||||
{
|
||||
M6502(config, m_audiocpu, JEDI_AUDIO_CPU_CLOCK);
|
||||
m_audiocpu->set_addrmap(AS_PROGRAM, &jedi_state::audio_map);
|
||||
|
||||
SPEAKER(config, "lspeaker").front_left();
|
||||
SPEAKER(config, "rspeaker").front_right();
|
||||
|
||||
pokey_device &pokey1(POKEY(config, "pokey1", JEDI_POKEY_CLOCK));
|
||||
pokey1.set_output_opamp(RES_K(1), 0.0, 5.0);
|
||||
pokey1.add_route(ALL_OUTPUTS, "lspeaker", 0.30);
|
||||
pokey1.add_route(ALL_OUTPUTS, "rspeaker", 0.30);
|
||||
|
||||
pokey_device &pokey2(POKEY(config, "pokey2", JEDI_POKEY_CLOCK));
|
||||
pokey2.set_output_opamp(RES_K(1), 0.0, 5.0);
|
||||
pokey2.add_route(ALL_OUTPUTS, "lspeaker", 0.30);
|
||||
pokey2.add_route(ALL_OUTPUTS, "rspeaker", 0.30);
|
||||
|
||||
pokey_device &pokey3(POKEY(config, "pokey3", JEDI_POKEY_CLOCK));
|
||||
pokey3.set_output_opamp(RES_K(1), 0.0, 5.0);
|
||||
pokey3.add_route(ALL_OUTPUTS, "lspeaker", 0.30);
|
||||
|
||||
pokey_device &pokey4(POKEY(config, "pokey4", JEDI_POKEY_CLOCK));
|
||||
pokey4.set_output_opamp(RES_K(1), 0.0, 5.0);
|
||||
pokey4.add_route(ALL_OUTPUTS, "rspeaker", 0.30);
|
||||
|
||||
TMS5220(config, m_tms, JEDI_TMS5220_CLOCK);
|
||||
m_tms->add_route(ALL_OUTPUTS, "lspeaker", 1.0);
|
||||
m_tms->add_route(ALL_OUTPUTS, "rspeaker", 1.0);
|
||||
|
||||
GENERIC_LATCH_8(config, m_soundlatch); // 5E (LS374) + 3E (LS279) pins 13-15
|
||||
GENERIC_LATCH_8(config, m_sacklatch); // 4E (LS374) + 3E (LS279) pins 1-4
|
||||
}
|
@ -1,402 +0,0 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Dan Boris, Aaron Giles
|
||||
/***************************************************************************
|
||||
|
||||
Atari Return of the Jedi hardware
|
||||
|
||||
driver by Dan Boris
|
||||
|
||||
Return of the Jedi has a peculiar playfield/motion object
|
||||
priority system. That is, there is no priority system ;-)
|
||||
The color of the pixel which appears on screen depends on
|
||||
all three of the foreground, background and motion objects.
|
||||
The 1024 colors palette is appropriately set up by the program
|
||||
to "emulate" a priority system, but it can also be used to display
|
||||
completely different colors (see the palette test in service mode)
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "jedi.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
/*************************************
|
||||
*
|
||||
* Start
|
||||
*
|
||||
*************************************/
|
||||
|
||||
void jedi_state::video_start()
|
||||
{
|
||||
#if DEBUG_GFXDECODE
|
||||
// the sprite pixel determines pen address bits A4-A7
|
||||
gfx_element *gx0 = m_gfxdecode->gfx(2);
|
||||
|
||||
// allocate memory for the assembled data
|
||||
m_gfxdata = std::make_unique<u8[]>(gx0->elements() * gx0->width() * gx0->height());
|
||||
|
||||
// loop over elements
|
||||
u8 *dest = m_gfxdata.get();
|
||||
for (int c = 0; c < gx0->elements(); c++)
|
||||
{
|
||||
const u8 *c0base = gx0->get_data(c);
|
||||
|
||||
// loop over height
|
||||
for (int y = 0; y < gx0->height(); y++)
|
||||
{
|
||||
const u8 *c0 = c0base;
|
||||
|
||||
for (int x = 0; x < gx0->width(); x++)
|
||||
{
|
||||
const u8 pix = (*c0++ & 0xf);
|
||||
*dest++ = pix << 4;
|
||||
}
|
||||
c0base += gx0->rowbytes();
|
||||
}
|
||||
}
|
||||
|
||||
gx0->set_raw_layout(m_gfxdata.get(), gx0->width(), gx0->height(), gx0->elements(), 8 * gx0->width(), 8 * gx0->width() * gx0->height());
|
||||
gx0->set_granularity(1);
|
||||
#endif
|
||||
|
||||
// register for saving
|
||||
save_item(NAME(m_vscroll));
|
||||
save_item(NAME(m_hscroll));
|
||||
save_item(NAME(m_foreground_bank));
|
||||
save_item(NAME(m_video_off));
|
||||
}
|
||||
|
||||
|
||||
WRITE_LINE_MEMBER(jedi_state::foreground_bank_w)
|
||||
{
|
||||
m_foreground_bank = state;
|
||||
}
|
||||
|
||||
|
||||
WRITE_LINE_MEMBER(jedi_state::video_off_w)
|
||||
{
|
||||
m_video_off = state;
|
||||
}
|
||||
|
||||
|
||||
/*************************************
|
||||
*
|
||||
* Palette RAM
|
||||
*
|
||||
*************************************
|
||||
*
|
||||
* Color RAM format
|
||||
* Color RAM is 1024x12
|
||||
*
|
||||
* RAM address: A0..A3 = Playfield color code
|
||||
* A4..A7 = Motion object color code
|
||||
* A8..A9 = Alphanumeric color code
|
||||
*
|
||||
* RAM data:
|
||||
* 0..2 = Blue
|
||||
* 3..5 = Green
|
||||
* 6..8 = Blue
|
||||
* 9..11 = Intensity
|
||||
*
|
||||
* Output resistor values:
|
||||
* bit 0 = 22K
|
||||
* bit 1 = 10K
|
||||
* bit 2 = 4.7K
|
||||
*
|
||||
*************************************/
|
||||
|
||||
rgb_t jedi_state::jedi_IRGB_3333(u32 raw)
|
||||
{
|
||||
const u8 intensity = (raw >> 9) & 7;
|
||||
u8 bits = (raw >> 6) & 7;
|
||||
const u8 r = 5 * bits * intensity;
|
||||
bits = (raw >> 3) & 7;
|
||||
const u8 g = 5 * bits * intensity;
|
||||
bits = (raw >> 0) & 7;
|
||||
const u8 b = 5 * bits * intensity;
|
||||
|
||||
return rgb_t(r, g, b);
|
||||
}
|
||||
|
||||
void jedi_state::do_pen_lookup(bitmap_rgb32 &bitmap, const rectangle &cliprect)
|
||||
{
|
||||
for (int y = cliprect.top(); y <= cliprect.bottom(); y++)
|
||||
for(int x = cliprect.left(); x <= cliprect.right(); x++)
|
||||
bitmap.pix(y, x) = m_palette->pen(bitmap.pix(y, x));
|
||||
}
|
||||
|
||||
|
||||
/*************************************
|
||||
*
|
||||
* Scroll offsets
|
||||
*
|
||||
*************************************/
|
||||
|
||||
void jedi_state::vscroll_w(offs_t offset, u8 data)
|
||||
{
|
||||
m_vscroll = data | (offset << 8);
|
||||
}
|
||||
|
||||
|
||||
void jedi_state::hscroll_w(offs_t offset, u8 data)
|
||||
{
|
||||
m_hscroll = data | (offset << 8);
|
||||
}
|
||||
|
||||
|
||||
/*************************************
|
||||
*
|
||||
* Background/text layer drawing
|
||||
* with smoothing
|
||||
*
|
||||
*************************************/
|
||||
|
||||
void jedi_state::draw_background_and_text(bitmap_rgb32 &bitmap, const rectangle &cliprect)
|
||||
{
|
||||
u8 background_line_buffer[0x200]; // RAM chip at 2A
|
||||
|
||||
const u8 *prom1 = &m_proms[0x0000 | ((*m_smoothing_table & 0x03) << 8)];
|
||||
const u8 *prom2 = &m_proms[0x0800 | ((*m_smoothing_table & 0x03) << 8)];
|
||||
|
||||
std::fill(std::begin(background_line_buffer), std::end(background_line_buffer), 0);
|
||||
|
||||
for (int y = cliprect.top(); y <= cliprect.bottom(); y++)
|
||||
{
|
||||
u8 bg_last_col = 0;
|
||||
|
||||
for (int x = cliprect.left(); x <= cliprect.right(); x += 2)
|
||||
{
|
||||
u16 tx_col1, tx_col2, bg_col = 0;
|
||||
|
||||
const int sy = y + m_vscroll;
|
||||
int sx = x + m_hscroll;
|
||||
|
||||
// determine offsets into video memory
|
||||
const offs_t tx_offs = ((y & 0xf8) << 3) | (x >> 3);
|
||||
const offs_t bg_offs = ((sy & 0x1f0) << 1) | ((sx & 0x1f0) >> 4);
|
||||
|
||||
// get the character codes
|
||||
const int tx_code = (m_foreground_bank << 8) | m_foregroundram[tx_offs];
|
||||
const int bg_bank = m_backgroundram[0x0400 | bg_offs];
|
||||
const int bg_code = m_backgroundram[0x0000 | bg_offs] |
|
||||
((bg_bank & 0x01) << 8) |
|
||||
((bg_bank & 0x08) << 6) |
|
||||
((bg_bank & 0x02) << 9);
|
||||
|
||||
// background flip X
|
||||
if (bg_bank & 0x04)
|
||||
sx = sx ^ 0x0f;
|
||||
|
||||
// calculate the address of the gfx data
|
||||
const offs_t tx_gfx_offs = (tx_code << 4) | ((y & 0x07) << 1) | ((( x & 0x04) >> 2));
|
||||
const offs_t bg_gfx_offs = (bg_code << 4) | (sy & 0x0e) | (((sx & 0x08) >> 3));
|
||||
|
||||
// get the gfx data
|
||||
const u8 tx_data = m_tx_gfx[ tx_gfx_offs];
|
||||
const u8 bg_data1 = m_bg_gfx[0x0000 | bg_gfx_offs];
|
||||
const u8 bg_data2 = m_bg_gfx[0x8000 | bg_gfx_offs];
|
||||
|
||||
// the text layer pixel determines pen address bits A8 and A9
|
||||
if (x & 0x02)
|
||||
{
|
||||
tx_col1 = ((tx_data & 0x0c) << 6);
|
||||
tx_col2 = ((tx_data & 0x03) << 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
tx_col1 = ((tx_data & 0xc0) << 2);
|
||||
tx_col2 = ((tx_data & 0x30) << 4);
|
||||
}
|
||||
|
||||
// the background pixel determines pen address bits A0-A3
|
||||
switch (sx & 0x06)
|
||||
{
|
||||
case 0x00: bg_col = ((bg_data1 & 0x80) >> 4) | ((bg_data1 & 0x08) >> 1) | ((bg_data2 & 0x80) >> 6) | ((bg_data2 & 0x08) >> 3); break;
|
||||
case 0x02: bg_col = ((bg_data1 & 0x40) >> 3) | ((bg_data1 & 0x04) >> 0) | ((bg_data2 & 0x40) >> 5) | ((bg_data2 & 0x04) >> 2); break;
|
||||
case 0x04: bg_col = ((bg_data1 & 0x20) >> 2) | ((bg_data1 & 0x02) << 1) | ((bg_data2 & 0x20) >> 4) | ((bg_data2 & 0x02) >> 1); break;
|
||||
case 0x06: bg_col = ((bg_data1 & 0x10) >> 1) | ((bg_data1 & 0x01) << 2) | ((bg_data2 & 0x10) >> 3) | ((bg_data2 & 0x01) >> 0); break;
|
||||
}
|
||||
|
||||
/* the first pixel is smoothed via a lookup using the current and last pixel value -
|
||||
the next pixel just uses the current value directly. After we done with a pixel
|
||||
save it for later in the line buffer RAM */
|
||||
const u8 bg_tempcol = prom1[(bg_last_col << 4) | bg_col];
|
||||
bitmap.pix(y, x + 0) = tx_col1 | prom2[(background_line_buffer[x + 0] << 4) | bg_tempcol];
|
||||
bitmap.pix(y, x + 1) = tx_col2 | prom2[(background_line_buffer[x + 1] << 4) | bg_col];
|
||||
background_line_buffer[x + 0] = bg_tempcol;
|
||||
background_line_buffer[x + 1] = bg_col;
|
||||
|
||||
bg_last_col = bg_col;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*************************************
|
||||
*
|
||||
* Sprite drawing
|
||||
*
|
||||
*************************************/
|
||||
|
||||
void jedi_state::draw_sprites(bitmap_rgb32 &bitmap, const rectangle &cliprect)
|
||||
{
|
||||
for (offs_t offs = 0x00; offs < 0x30; offs++)
|
||||
{
|
||||
int y_size;
|
||||
|
||||
// coordinates adjustments made to match screenshot
|
||||
u8 y = 240 - m_spriteram[offs + 0x80] + 1;
|
||||
const bool flip_x = m_spriteram[offs + 0x40] & 0x10;
|
||||
const bool flip_y = m_spriteram[offs + 0x40] & 0x20;
|
||||
const bool tall = m_spriteram[offs + 0x40] & 0x08;
|
||||
|
||||
// shuffle the bank bits in
|
||||
u16 code = m_spriteram[offs] |
|
||||
((m_spriteram[offs + 0x40] & 0x04) << 8) |
|
||||
((m_spriteram[offs + 0x40] & 0x40) << 3) |
|
||||
((m_spriteram[offs + 0x40] & 0x02) << 7);
|
||||
|
||||
// adjust for double-height
|
||||
if (tall)
|
||||
{
|
||||
code &= ~1;
|
||||
y_size = 0x20;
|
||||
y = y - 0x10;
|
||||
}
|
||||
else
|
||||
y_size = 0x10;
|
||||
|
||||
const u8 *gfx = &m_spr_gfx[code << 5];
|
||||
|
||||
if (flip_y)
|
||||
y = y + y_size - 1;
|
||||
|
||||
for (int sy = 0; sy < y_size; sy++)
|
||||
{
|
||||
u16 x = m_spriteram[offs + 0x100] + ((m_spriteram[offs + 0x40] & 0x01) << 8) - 2;
|
||||
|
||||
if (flip_x)
|
||||
x = x + 7;
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
u8 data1 = *(0x00000 + gfx);
|
||||
u8 data2 = *(0x10000 + gfx);
|
||||
|
||||
for (int sx = 0; sx < 4; sx++)
|
||||
{
|
||||
// the sprite pixel determines pen address bits A4-A7
|
||||
const u32 col = ((data1 & 0x80) >> 0) | ((data1 & 0x08) << 3) | ((data2 & 0x80) >> 2) | ((data2 & 0x08) << 1);
|
||||
|
||||
x = x & 0x1ff;
|
||||
|
||||
if (col && cliprect.contains(x, y))
|
||||
bitmap.pix(y, x) = (bitmap.pix(y, x) & 0x30f) | col;
|
||||
|
||||
// next pixel
|
||||
if (flip_x)
|
||||
x = x - 1;
|
||||
else
|
||||
x = x + 1;
|
||||
|
||||
data1 = data1 << 1;
|
||||
data2 = data2 << 1;
|
||||
}
|
||||
|
||||
gfx = gfx + 1;
|
||||
}
|
||||
|
||||
if (flip_y)
|
||||
y = y - 1;
|
||||
else
|
||||
y = y + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*************************************
|
||||
*
|
||||
* Core video refresh
|
||||
*
|
||||
*************************************/
|
||||
|
||||
u32 jedi_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
|
||||
{
|
||||
// if no video, clear it all to black
|
||||
if (m_video_off)
|
||||
bitmap.fill(rgb_t::black(), cliprect);
|
||||
else
|
||||
{
|
||||
// draw the background/text layers, followed by the sprites - it needs to be done in this order
|
||||
draw_background_and_text(bitmap, cliprect);
|
||||
draw_sprites(bitmap, cliprect);
|
||||
do_pen_lookup(bitmap, cliprect);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*************************************
|
||||
*
|
||||
* Machine driver
|
||||
*
|
||||
*************************************/
|
||||
|
||||
#if DEBUG_GFXDECODE
|
||||
static const gfx_layout text_layout =
|
||||
{
|
||||
8, 8,
|
||||
RGN_FRAC(1,1),
|
||||
2,
|
||||
{ 0, 1 },
|
||||
{ STEP8(0, 2) },
|
||||
{ STEP8(0, 2*8) },
|
||||
8*8*2
|
||||
};
|
||||
|
||||
static const gfx_layout bg_layout =
|
||||
{
|
||||
8, 8,
|
||||
RGN_FRAC(1,2),
|
||||
4,
|
||||
{ 0, 4, RGN_FRAC(1,2)+0, RGN_FRAC(1,2)+4 },
|
||||
{ STEP4(0, 1), STEP4(4*2, 1) },
|
||||
{ STEP8(0, 4*2*2) },
|
||||
8*8*2
|
||||
};
|
||||
|
||||
static const gfx_layout sprite_layout =
|
||||
{
|
||||
8, 16,
|
||||
RGN_FRAC(1,2),
|
||||
4,
|
||||
{ 0, 4, RGN_FRAC(1,2)+0, RGN_FRAC(1,2)+4 },
|
||||
{ STEP4(0, 1), STEP4(4*2, 1) },
|
||||
{ STEP16(0, 4*2*2) },
|
||||
8*16*2
|
||||
};
|
||||
|
||||
static GFXDECODE_START( gfx_jedi )
|
||||
GFXDECODE_ENTRY( "tx_gfx", 0, text_layout, 0, 0x400/0x04 )
|
||||
GFXDECODE_SCALE( "bg_gfx", 0, bg_layout, 0, 0x400/0x10, 2, 2 ) // 8x8 but internally expanded related with smoothing
|
||||
GFXDECODE_ENTRY( "spr_gfx", 0, sprite_layout, 0, 0x310 )
|
||||
GFXDECODE_END
|
||||
#endif
|
||||
|
||||
void jedi_state::jedi_video(machine_config &config)
|
||||
{
|
||||
#if DEBUG_GFXDECODE
|
||||
GFXDECODE(config, m_gfxdecode, m_palette, gfx_jedi);
|
||||
#endif
|
||||
SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
|
||||
m_screen->set_refresh_hz(60);
|
||||
m_screen->set_size(64*8, 262); // verify vert size
|
||||
m_screen->set_visarea(0*8, 37*8-1, 0*8, 30*8-1);
|
||||
m_screen->set_screen_update(FUNC(jedi_state::screen_update));
|
||||
|
||||
PALETTE(config, m_palette).set_format(2, &jedi_state::jedi_IRGB_3333, 0x400);
|
||||
}
|
Loading…
Reference in New Issue
Block a user