mirror of
https://github.com/holub/mame
synced 2025-04-24 17:30:55 +03:00
nmk/nmk214.cpp: Added NMK214 graphics unscrambling device. (#12039)
The current implementation is less than ideal due to inflexibility of device_gfx_interface. nmk/nmk16.cpp: Hooked up NMK214 device for sabotenb.
This commit is contained in:
parent
34e362e9d5
commit
3b02100587
@ -208,6 +208,7 @@ Reference of music tempo:
|
||||
#include "sound/ymopn.h"
|
||||
#include "sound/ymopl.h"
|
||||
|
||||
#include "multibyte.h"
|
||||
#include "screen.h"
|
||||
#include "speaker.h"
|
||||
|
||||
@ -4358,14 +4359,43 @@ u8 tdragon_prot_state::mcu_port6_r()
|
||||
|
||||
void tdragon_prot_state::machine_start()
|
||||
{
|
||||
nmk16_state::machine_start();
|
||||
|
||||
save_item(NAME(m_bus_status));
|
||||
}
|
||||
|
||||
void tdragon_prot_state::machine_reset()
|
||||
{
|
||||
nmk16_state::machine_reset();
|
||||
|
||||
m_bus_status = 0x04;
|
||||
}
|
||||
|
||||
void tdragon_prot_214_state::device_post_load()
|
||||
{
|
||||
tdragon_prot_state::device_post_load();
|
||||
|
||||
if (m_gfx_unscramble_enabled && !m_gfx_decoded)
|
||||
{
|
||||
// Loaded a state saved after graphics were decoded before decoding graphics
|
||||
// Force graphics unscrambling now
|
||||
decode_nmk214();
|
||||
m_gfxdecode->gfx(1)->mark_all_dirty(); // background tiles
|
||||
m_gfxdecode->gfx(2)->mark_all_dirty(); // sprites
|
||||
m_bg_tilemap[0]->mark_all_dirty();
|
||||
m_gfx_decoded = true;
|
||||
}
|
||||
}
|
||||
|
||||
void tdragon_prot_214_state::machine_start()
|
||||
{
|
||||
tdragon_prot_state::machine_start();
|
||||
|
||||
save_item(NAME(m_init_data_nmk214));
|
||||
save_item(NAME(m_init_clock_nmk214));
|
||||
save_item(NAME(m_gfx_unscramble_enabled));
|
||||
}
|
||||
|
||||
void tdragon_prot_state::mcu_side_shared_w(offs_t offset, u8 data)
|
||||
{
|
||||
LOG("%s: mcu_side_shared_w offset %08x (data %02x)\n", machine().describe_context(), offset, data);
|
||||
@ -4899,32 +4929,74 @@ void nmk16_state::bjtwin(machine_config &config)
|
||||
nmk112.set_rom1_tag("oki2");
|
||||
}
|
||||
|
||||
// the 215 writes minimal data here, probably only enables the decryption logic, rather than supplying the decryption table
|
||||
void tdragon_prot_state::mcu_port3_to_214_w(u8 data)
|
||||
// The 215 writes minimal data here to select an unscrambling configuration hardwired inside the NMK214 chip.
|
||||
void tdragon_prot_214_state::mcu_port3_to_214_w(u8 data)
|
||||
{
|
||||
// startup only
|
||||
logerror("%s: mcu_port3_to_214_w (data %02x)\n", machine().describe_context(), data);
|
||||
LOG("%s: mcu_port3_to_214_w (data %02x)\n", machine().describe_context(), data);
|
||||
|
||||
// Startup only. Bit 2 on Port 3 of MCU (NMK215) acts as strobe/clock (rising edge) for storing the byte previously set on the Port 7
|
||||
// of MCU (NMK215) into the internal registers of both NMK214 devices
|
||||
if (m_init_clock_nmk214 == 0 && BIT(data, 2) == 1)
|
||||
{
|
||||
// Value is sent to both devices at the same time. Internally, each one evaluates if the value should be stored or not based on
|
||||
// bit 3 of the incoming value matches to the operation mode configured on each device:
|
||||
m_nmk214[0]->set_init_config(m_init_data_nmk214);
|
||||
m_nmk214[1]->set_init_config(m_init_data_nmk214);
|
||||
|
||||
// Force decode gfx after setting both nmk214 init config, just for testing purposes. Real devices perform the decoding on the fly
|
||||
// for each byte/word fetch from GFX ROMs
|
||||
if (!m_gfx_unscramble_enabled && m_nmk214[0]->is_device_initialized() && m_nmk214[1]->is_device_initialized())
|
||||
{
|
||||
m_gfx_unscramble_enabled = true;
|
||||
if (!m_gfx_decoded)
|
||||
{
|
||||
decode_nmk214();
|
||||
m_gfxdecode->gfx(1)->mark_all_dirty(); // background tiles
|
||||
m_gfxdecode->gfx(2)->mark_all_dirty(); // sprites
|
||||
m_bg_tilemap[0]->mark_all_dirty();
|
||||
m_gfx_decoded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_init_clock_nmk214 = BIT(data, 2);
|
||||
}
|
||||
|
||||
void tdragon_prot_state::mcu_port7_to_214_w(u8 data)
|
||||
void tdragon_prot_214_state::mcu_port7_to_214_w(u8 data)
|
||||
{
|
||||
// startup only
|
||||
logerror("%s: mcu_port7_to_214_w (data %02x)\n", machine().describe_context(), data);
|
||||
LOG("%s: mcu_port7_to_214_w (data %02x)\n", machine().describe_context(), data);
|
||||
|
||||
// Startup only. Value written here is kept as outputs on Port 7 of MCU (NMK215) in order to be read by the NMK214 devices when the
|
||||
// clock signal is sent (Bit 2 of Port 3)
|
||||
m_init_data_nmk214 = data;
|
||||
}
|
||||
|
||||
void tdragon_prot_state::saboten_prot(machine_config &config)
|
||||
// Bitswaps that represent how the address bus of the NMK214s (13 bits) are hooked up related to the address bus of the ROMs.
|
||||
// Every element represents the bit number in the ROM address bus that should be taken for each NMK214 address bus position, starting by the LSB
|
||||
static const std::array<u8, 13> nmk214_sprites_address_bitswap = {0, 1, 2, 3, 10, 12, 13, 14, 15, 16, 17, 18, 19};
|
||||
static const std::array<u8, 13> nmk214_bg_address_bitswap = {0, 1, 2, 3, 11, 13, 14, 15, 16, 17, 18, 19, 20};
|
||||
|
||||
void tdragon_prot_214_state::saboten_prot(machine_config &config)
|
||||
{
|
||||
bjtwin(config);
|
||||
|
||||
TMP90840(config, m_protcpu, 4000000); // Toshiba TMP90840 marked as NMK-215, with 8Kbyte internal ROM, 256bytes internal RAM
|
||||
m_protcpu->set_addrmap(AS_PROGRAM, &tdragon_prot_state::tdragon_prot_map);
|
||||
m_protcpu->port_write<6>().set(FUNC(tdragon_prot_state::mcu_port6_w));
|
||||
m_protcpu->port_read<5>().set(FUNC(tdragon_prot_state::mcu_port5_r));
|
||||
m_protcpu->port_read<6>().set(FUNC(tdragon_prot_state::mcu_port6_r));
|
||||
m_protcpu->set_addrmap(AS_PROGRAM, &tdragon_prot_214_state::tdragon_prot_map);
|
||||
m_protcpu->port_write<6>().set(FUNC(tdragon_prot_214_state::mcu_port6_w));
|
||||
m_protcpu->port_read<5>().set(FUNC(tdragon_prot_214_state::mcu_port5_r));
|
||||
m_protcpu->port_read<6>().set(FUNC(tdragon_prot_214_state::mcu_port6_r));
|
||||
|
||||
// the 215 has these hooked up, going to the 214
|
||||
m_protcpu->port_write<3>().set(FUNC(tdragon_prot_state::mcu_port3_to_214_w));
|
||||
m_protcpu->port_write<7>().set(FUNC(tdragon_prot_state::mcu_port7_to_214_w));
|
||||
m_protcpu->port_write<3>().set(FUNC(tdragon_prot_214_state::mcu_port3_to_214_w));
|
||||
m_protcpu->port_write<7>().set(FUNC(tdragon_prot_214_state::mcu_port7_to_214_w));
|
||||
|
||||
NMK214(config, m_nmk214[0], 0); // Descrambling device for sprite GFX data
|
||||
m_nmk214[0]->set_mode(0);
|
||||
m_nmk214[0]->set_input_address_bitswap(nmk214_sprites_address_bitswap);
|
||||
|
||||
NMK214(config, m_nmk214[1], 0); // Descrambling device for BG GFX data
|
||||
m_nmk214[1]->set_mode(1);
|
||||
m_nmk214[1]->set_input_address_bitswap(nmk214_bg_address_bitswap);
|
||||
|
||||
config.set_maximum_quantum(attotime::from_hz(6000));
|
||||
}
|
||||
@ -5118,6 +5190,32 @@ void nmk16_state::decode_gfx()
|
||||
}
|
||||
}
|
||||
|
||||
void tdragon_prot_214_state::decode_nmk214()
|
||||
{
|
||||
u8 *rom;
|
||||
int len;
|
||||
|
||||
// background tiles
|
||||
rom = memregion("bgtile")->base();
|
||||
len = memregion("bgtile")->bytes();
|
||||
for (int A = 0; A < len; A++)
|
||||
{
|
||||
rom[A] = m_nmk214[1]->decode_byte(A, rom[A]);
|
||||
}
|
||||
|
||||
// sprites
|
||||
rom = memregion("sprites")->base();
|
||||
len = memregion("sprites")->bytes();
|
||||
for (int A = 0; A < (len - 1); A += 2)
|
||||
{
|
||||
// sprite ROM is 16-bit big Endian
|
||||
u16 word = get_u16be(&rom[A]);
|
||||
|
||||
// A is a byte address, divide by 2 to give word address for NMK214
|
||||
put_u16be(&rom[A], m_nmk214[0]->decode_word(A/2, word));
|
||||
}
|
||||
}
|
||||
|
||||
void nmk16_state::decode_tdragonb()
|
||||
{
|
||||
/* Descrambling Info Again Taken from Raine, Huge Thanks to Antiriad and the Raine Team for
|
||||
@ -8981,8 +9079,8 @@ GAME( 1994, raphero, arcadian, raphero, raphero, nmk16_state, init_
|
||||
GAME( 1994, rapheroa, arcadian, raphero, raphero, nmk16_state, init_banked_audiocpu, ROT270, "NMK (Media Trading license)", "Rapid Hero (Media Trading)", 0 ) // ^^ - note that all ROM sets have Media Trading(aka Media Shoji) in the tile graphics, but this is the only set that shows it on the titlescreen
|
||||
|
||||
// both sets of both these games show a date of 9th Mar 1992 in the test mode, they look like different revisions so I doubt this is accurate
|
||||
GAME( 1992, sabotenb, 0, saboten_prot, sabotenb, tdragon_prot_state, init_nmk, ROT0, "NMK / Tecmo", "Saboten Bombers (set 1)", MACHINE_NO_COCKTAIL )
|
||||
GAME( 1992, sabotenba, sabotenb, saboten_prot, sabotenb, tdragon_prot_state, init_nmk, ROT0, "NMK / Tecmo", "Saboten Bombers (set 2)", MACHINE_NO_COCKTAIL )
|
||||
GAME( 1992, sabotenb, 0, saboten_prot, sabotenb, tdragon_prot_214_state, empty_init,ROT0, "NMK / Tecmo", "Saboten Bombers (set 1)", MACHINE_NO_COCKTAIL )
|
||||
GAME( 1992, sabotenba, sabotenb, saboten_prot, sabotenb, tdragon_prot_214_state, empty_init,ROT0, "NMK / Tecmo", "Saboten Bombers (set 2)", MACHINE_NO_COCKTAIL )
|
||||
GAME( 1992, cactus, sabotenb, bjtwin, sabotenb, nmk16_state, init_nmk, ROT0, "bootleg", "Cactus (bootleg of Saboten Bombers)", MACHINE_NO_COCKTAIL ) // PCB marked 'Cactus', no title screen
|
||||
|
||||
GAME( 1993, bjtwin, 0, bjtwin, bjtwin, nmk16_state, init_bjtwin, ROT270, "NMK", "Bombjack Twin (set 1)", MACHINE_NO_COCKTAIL )
|
||||
|
@ -7,6 +7,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "nmk004.h"
|
||||
#include "nmk214.h"
|
||||
#include "nmk16spr.h"
|
||||
|
||||
#include "seibusound.h"
|
||||
@ -241,14 +242,13 @@ public:
|
||||
tdragon_prot_state(const machine_config &mconfig, device_type type, const char *tag) :
|
||||
nmk16_state(mconfig, type, tag),
|
||||
m_protcpu(*this, "protcpu")
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
void tdragon_prot(machine_config &config);
|
||||
void hachamf_prot(machine_config &config);
|
||||
void saboten_prot(machine_config &config);
|
||||
|
||||
protected:
|
||||
|
||||
virtual void machine_start() override;
|
||||
virtual void machine_reset() override;
|
||||
|
||||
@ -263,10 +263,40 @@ protected:
|
||||
u8 mcu_port6_r();
|
||||
u8 mcu_port7_r(); // NMK-113 uses this
|
||||
|
||||
u8 m_bus_status;
|
||||
};
|
||||
|
||||
class tdragon_prot_214_state : public tdragon_prot_state
|
||||
{
|
||||
public:
|
||||
tdragon_prot_214_state(const machine_config &mconfig, device_type type, const char *tag) :
|
||||
tdragon_prot_state(mconfig, type, tag),
|
||||
m_nmk214(*this, "nmk214_%u", 0U),
|
||||
m_init_data_nmk214(0),
|
||||
m_init_clock_nmk214(0),
|
||||
m_gfx_unscramble_enabled(false),
|
||||
m_gfx_decoded(false)
|
||||
{
|
||||
}
|
||||
|
||||
void saboten_prot(machine_config &config);
|
||||
|
||||
protected:
|
||||
virtual void device_post_load() override;
|
||||
virtual void machine_start() override;
|
||||
|
||||
private:
|
||||
void decode_nmk214();
|
||||
|
||||
void mcu_port3_to_214_w(u8 data);
|
||||
void mcu_port7_to_214_w(u8 data);
|
||||
|
||||
u8 m_bus_status;
|
||||
required_device_array<nmk214_device, 2> m_nmk214;
|
||||
|
||||
u8 m_init_data_nmk214;
|
||||
u8 m_init_clock_nmk214;
|
||||
bool m_gfx_unscramble_enabled;
|
||||
bool m_gfx_decoded; // excluded from save states
|
||||
};
|
||||
|
||||
class afega_state : public nmk16_state
|
||||
|
213
src/mame/nmk/nmk214.cpp
Normal file
213
src/mame/nmk/nmk214.cpp
Normal file
@ -0,0 +1,213 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Sergio Galiano
|
||||
/*
|
||||
NMK214 GFX Descrambler emulation
|
||||
|
||||
This device is used for descrambling the GFX data on some game PCBs from NMK (nmk16).
|
||||
It works in tandem with NMK215, that's a Toshiba MCU which sends initialization data to NMK214 in order to do the
|
||||
descrambling process.
|
||||
Every game PCB using it has two NMK214 chips, one for sprites and another for background tiles.
|
||||
It can work in two different modes: word and byte:
|
||||
For sprites it always works in word mode; for backgrounds it always works in byte mode.
|
||||
There are 8 hard-wired internal configurations. The data received from NMK215 selects one of those them at startup.
|
||||
That init data is stored in the device when bit 3 matches with the operation mode wired directly on the PCB.
|
||||
The descrambling process is essentially a dynamic bitswap of the incoming word/byte data, doing a different bitswap
|
||||
based on the address of the data to be descrambled.
|
||||
The input address bus on the device is used to determine which bitswap do for each word/byte, and it's usually
|
||||
hooked differently for sprites and background tiles, so an 'input_address_bitswap' is included to get the effective
|
||||
address the device will use.
|
||||
*/
|
||||
|
||||
|
||||
#include "emu.h"
|
||||
#include "nmk214.h"
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
const std::array<u8, 13> default_input_address_bitswap = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
|
||||
|
||||
// Static byte values for each of the 8 different hardwired configurations.
|
||||
// One bit will be taken from each byte in the selected config (row), and those
|
||||
// 3 bits will be used to select the output bitswap down below:
|
||||
const u8 init_configs[8][3] =
|
||||
{
|
||||
{0xaa, 0xcc, 0xf0}, // Predefined config 0
|
||||
{0x55, 0x39, 0x1e}, // Predefined config 1
|
||||
{0xc5, 0x69, 0x5c}, // Predefined config 2
|
||||
{0x35, 0x5c, 0xc5}, // Predefined config 3
|
||||
{0x78, 0x1d, 0x2e}, // Predefined config 4
|
||||
{0x55, 0x33, 0x0f}, // Predefined config 5
|
||||
{0xa5, 0xb8, 0x36}, // Predefined config 6
|
||||
{0x8b, 0x69, 0x2e} // Predefined config 7
|
||||
};
|
||||
|
||||
// 3 values for each configuration to determine which lines from input address
|
||||
// bus are used to select a bit from hardwired config byte values above:
|
||||
const u8 selection_address_bits[8][3] =
|
||||
{
|
||||
{0x8, 0x9, 0xa}, // A8, A9 and A10 for predefined config 0
|
||||
{0x6, 0x8, 0xb}, // A6, A8 and A11 for predefined config 1
|
||||
{0x3, 0x9, 0xc}, // A3, A9 and A12 for predefined config 2
|
||||
{0x3, 0x7, 0xa}, // A3, A7 and A10 for predefined config 3
|
||||
{0x2, 0x5, 0xb}, // A2, A5 and A11 for predefined config 4
|
||||
{0x1, 0x4, 0xa}, // A1, A4 and A10 for predefined config 5
|
||||
{0x2, 0x4, 0xa}, // A2, A4 and A10 for predefined config 6
|
||||
{0x0, 0x4, 0xc} // A0, A4 and A12 for predefined config 7
|
||||
};
|
||||
|
||||
// Output word data bitswaps hardwired inside the chip.
|
||||
// Each value in the same column represents which bit from input data word is
|
||||
// used for current bit position in the output word.
|
||||
const u8 output_word_bitswaps[8][16] =
|
||||
{
|
||||
// D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 D10 D11 D12 D13 D14 D15
|
||||
{0x2, 0x3, 0x7, 0x8, 0xc, 0x4, 0xb, 0x9, 0x1, 0xf, 0xa, 0x5, 0xe, 0x6, 0xd, 0x0}, // word bitswap 0
|
||||
{0x0, 0x3, 0x8, 0x7, 0xa, 0xc, 0x4, 0x1, 0xf, 0x9, 0x6, 0xd, 0xe, 0xb, 0x5, 0x2}, // word bitswap 1
|
||||
{0x9, 0x8, 0x2, 0x3, 0x6, 0x5, 0xd, 0xf, 0x7, 0x0, 0xc, 0xb, 0xa, 0x4, 0xe, 0x1}, // word bitswap 2
|
||||
{0x0, 0x3, 0x9, 0xf, 0xd, 0xc, 0xb, 0x1, 0x2, 0x7, 0xe, 0x6, 0x4, 0xa, 0x5, 0x8}, // word bitswap 3
|
||||
{0x1, 0x3, 0xf, 0x7, 0xd, 0xa, 0xe, 0x9, 0x0, 0x8, 0xc, 0x4, 0x6, 0x5, 0xb, 0x2}, // word bitswap 4
|
||||
{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf}, // word bitswap 5
|
||||
{0x0, 0xf, 0x3, 0x2, 0xe, 0x4, 0x6, 0x7, 0x8, 0x9, 0x5, 0xd, 0xc, 0xb, 0xa, 0x1}, // word bitswap 6
|
||||
{0xf, 0x2, 0x3, 0x1, 0xb, 0xe, 0xd, 0x8, 0x7, 0x0, 0x4, 0xc, 0x6, 0xa, 0x5, 0x9} // word bitswap 7
|
||||
};
|
||||
|
||||
// Output byte data bitswaps hardwired inside the chip.
|
||||
// Values on the table are calculated from the above word-bitswaps based on the
|
||||
// following input data lines correlation (that's how the data lines are hooked
|
||||
// up in real hardware):
|
||||
/*
|
||||
BYTE mode | WORD mode
|
||||
----------|----------
|
||||
D0 | D13
|
||||
D1 | D10
|
||||
D2 | D4
|
||||
D3 | D12
|
||||
D4 | D6
|
||||
D5 | D14
|
||||
D6 | D11
|
||||
D7 | D5
|
||||
*/
|
||||
const u8 output_byte_bitswaps[8][8] =
|
||||
{
|
||||
// D0 D1 D2 D3 D4 D5 D6 D7
|
||||
{0x4, 0x1, 0x3, 0x5, 0x6, 0x0, 0x7, 0x2}, // byte bitswap 0
|
||||
{0x6, 0x4, 0x1, 0x5, 0x2, 0x7, 0x0, 0x3}, // byte bitswap 1
|
||||
{0x2, 0x3, 0x4, 0x1, 0x0, 0x5, 0x6, 0x7}, // byte bitswap 2
|
||||
{0x1, 0x5, 0x0, 0x2, 0x6, 0x7, 0x4, 0x3}, // byte bitswap 3
|
||||
{0x7, 0x3, 0x0, 0x4, 0x5, 0x6, 0x2, 0x1}, // byte bitswap 4
|
||||
{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7}, // byte bitswap 5
|
||||
{0x6, 0x7, 0x5, 0x3, 0x4, 0x1, 0x0, 0x2}, // byte bitswap 6
|
||||
{0x1, 0x2, 0x6, 0x4, 0x0, 0x7, 0x3, 0x5} // byte bitswap 7
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
DEFINE_DEVICE_TYPE(NMK214, nmk214_device, "nmk214", "NMK214 Graphics Descrambler")
|
||||
|
||||
nmk214_device::nmk214_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: device_t(mconfig, NMK214, tag, owner, clock)
|
||||
, m_mode(0)
|
||||
, m_input_address_bitswap(default_input_address_bitswap)
|
||||
, m_init_config(0)
|
||||
, m_device_initialized(false)
|
||||
{
|
||||
}
|
||||
|
||||
u8 nmk214_device::get_bitswap_select_value(u32 addr) const noexcept
|
||||
{
|
||||
// as the address lines could be hooked up in different order/positions on
|
||||
// the game PCB, reorder it and get the effective address to use:
|
||||
const u32 effective_address = bitswap<13>(addr,
|
||||
m_input_address_bitswap[12],
|
||||
m_input_address_bitswap[11],
|
||||
m_input_address_bitswap[10],
|
||||
m_input_address_bitswap[9],
|
||||
m_input_address_bitswap[8],
|
||||
m_input_address_bitswap[7],
|
||||
m_input_address_bitswap[6],
|
||||
m_input_address_bitswap[5],
|
||||
m_input_address_bitswap[4],
|
||||
m_input_address_bitswap[3],
|
||||
m_input_address_bitswap[2],
|
||||
m_input_address_bitswap[1],
|
||||
m_input_address_bitswap[0]);
|
||||
|
||||
// get selection address using only 3 bits of the effective address, based
|
||||
// on the initial config selected while device initialization:
|
||||
const u8 selection_address = bitswap<3>(effective_address,
|
||||
selection_address_bits[m_init_config][2],
|
||||
selection_address_bits[m_init_config][1],
|
||||
selection_address_bits[m_init_config][0]);
|
||||
|
||||
// get the bitswap selection value, using the previously computed selection
|
||||
// address and the selected internal config values:
|
||||
return (BIT(init_configs[m_init_config][0], selection_address) << 0)
|
||||
| (BIT(init_configs[m_init_config][1], selection_address) << 1)
|
||||
| (BIT(init_configs[m_init_config][2], selection_address) << 2);
|
||||
}
|
||||
|
||||
u16 nmk214_device::decode_word(u32 addr, u16 data) const noexcept
|
||||
{
|
||||
// compute the select value to choose which bitswap apply to the input word,
|
||||
// based on the address where the data is located
|
||||
const u8 bitswap_select = get_bitswap_select_value(addr);
|
||||
|
||||
return bitswap<16>(data,
|
||||
output_word_bitswaps[bitswap_select][15],
|
||||
output_word_bitswaps[bitswap_select][14],
|
||||
output_word_bitswaps[bitswap_select][13],
|
||||
output_word_bitswaps[bitswap_select][12],
|
||||
output_word_bitswaps[bitswap_select][11],
|
||||
output_word_bitswaps[bitswap_select][10],
|
||||
output_word_bitswaps[bitswap_select][9],
|
||||
output_word_bitswaps[bitswap_select][8],
|
||||
output_word_bitswaps[bitswap_select][7],
|
||||
output_word_bitswaps[bitswap_select][6],
|
||||
output_word_bitswaps[bitswap_select][5],
|
||||
output_word_bitswaps[bitswap_select][4],
|
||||
output_word_bitswaps[bitswap_select][3],
|
||||
output_word_bitswaps[bitswap_select][2],
|
||||
output_word_bitswaps[bitswap_select][1],
|
||||
output_word_bitswaps[bitswap_select][0]);
|
||||
}
|
||||
|
||||
u8 nmk214_device::decode_byte(u32 addr, u8 data) const noexcept
|
||||
{
|
||||
// compute the select value to choose which bitswap apply to the input byte,
|
||||
// based on the address where the data is located
|
||||
u8 bitswap_select = get_bitswap_select_value(addr);
|
||||
|
||||
return bitswap<8>(data,
|
||||
output_byte_bitswaps[bitswap_select][7],
|
||||
output_byte_bitswaps[bitswap_select][6],
|
||||
output_byte_bitswaps[bitswap_select][5],
|
||||
output_byte_bitswaps[bitswap_select][4],
|
||||
output_byte_bitswaps[bitswap_select][3],
|
||||
output_byte_bitswaps[bitswap_select][2],
|
||||
output_byte_bitswaps[bitswap_select][1],
|
||||
output_byte_bitswaps[bitswap_select][0]);
|
||||
}
|
||||
|
||||
void nmk214_device::set_init_config(u8 init_config) noexcept
|
||||
{
|
||||
// store config data only if Bit 3 matches with the operation mode of the device
|
||||
if (BIT(init_config, 3) == m_mode)
|
||||
{
|
||||
m_init_config = init_config & 0x7;
|
||||
m_device_initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
void nmk214_device::device_start()
|
||||
{
|
||||
save_item(NAME(m_init_config));
|
||||
save_item(NAME(m_device_initialized));
|
||||
}
|
||||
|
||||
void nmk214_device::device_reset()
|
||||
{
|
||||
m_init_config = 0;
|
||||
m_device_initialized = false;
|
||||
}
|
54
src/mame/nmk/nmk214.h
Normal file
54
src/mame/nmk/nmk214.h
Normal file
@ -0,0 +1,54 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Sergio Galiano
|
||||
#ifndef MAME_NMK_NMK214_H
|
||||
#define MAME_NMK_NMK214_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
|
||||
|
||||
class nmk214_device : public device_t
|
||||
{
|
||||
public:
|
||||
nmk214_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
void set_mode(const u8 mode) { m_mode = mode; }
|
||||
void set_input_address_bitswap(const std::array<u8, 13> &input_address_bitswap) { m_input_address_bitswap = input_address_bitswap; }
|
||||
|
||||
void set_init_config(u8 init_config) noexcept;
|
||||
bool is_device_initialized() const noexcept { return m_device_initialized; }
|
||||
|
||||
u16 decode_word(u32 addr, u16 data) const noexcept;
|
||||
u8 decode_byte(u32 addr, u8 data) const noexcept;
|
||||
|
||||
protected:
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
|
||||
private:
|
||||
// Operation mode - in practice, only LSB is used.
|
||||
// Allowed values: 0 or 1.
|
||||
// This is hard-wired on the PCB, with opposite values for the two devices.
|
||||
u8 m_mode;
|
||||
|
||||
// Input address lines bitswap.
|
||||
// Represents how the 13 NMK214 address lines are wired to the graphics ROM address bus.
|
||||
std::array<u8, 13> m_input_address_bitswap;
|
||||
|
||||
// Selects between eight internal configurations.
|
||||
// Bits 0 to 2 select the configuration.
|
||||
// Bit 3 must be set to match the operation mode for the configuration to take effect.
|
||||
u8 m_init_config;
|
||||
|
||||
// Indicates that the device has been configured and can perform descrambling.
|
||||
bool m_device_initialized;
|
||||
|
||||
|
||||
// Gets the bitswap index for a given data address.
|
||||
u8 get_bitswap_select_value(u32 addr) const noexcept;
|
||||
};
|
||||
|
||||
DECLARE_DEVICE_TYPE(NMK214, nmk214_device)
|
||||
|
||||
#endif // MAME_NMK_NMK214_H
|
Loading…
Reference in New Issue
Block a user