naomi: Split the rom boards into a collection of devices. [O. Galibert]

This commit is contained in:
Olivier Galibert 2011-08-23 18:47:49 +00:00
parent ca3a17ace0
commit 2393deea86
29 changed files with 4128 additions and 4118 deletions

4
.gitattributes vendored
View File

@ -3323,7 +3323,6 @@ src/mame/includes/namcos21.h svneol=native#text/plain
src/mame/includes/namcos22.h svneol=native#text/plain
src/mame/includes/namcos86.h svneol=native#text/plain
src/mame/includes/naomi.h svneol=native#text/plain
src/mame/includes/naomibd.h svneol=native#text/plain
src/mame/includes/naughtyb.h svneol=native#text/plain
src/mame/includes/nb1413m3.h svneol=native#text/plain
src/mame/includes/nb1414m4.h svneol=native#text/plain
@ -3861,7 +3860,6 @@ src/mame/machine/gaelco3d.h svneol=native#text/plain
src/mame/machine/gaelcrpt.c svneol=native#text/plain
src/mame/machine/galaxold.c svneol=native#text/plain
src/mame/machine/gaplus.c svneol=native#text/plain
src/mame/machine/gdcrypt.c svneol=native#text/plain
src/mame/machine/gdrom.c svneol=native#text/plain
src/mame/machine/gdrom.h svneol=native#text/plain
src/mame/machine/harddriv.c svneol=native#text/plain
@ -3944,8 +3942,6 @@ src/mame/machine/naomim2.c svneol=native#text/plain
src/mame/machine/naomim2.h svneol=native#text/plain
src/mame/machine/naomim4.c svneol=native#text/plain
src/mame/machine/naomim4.h svneol=native#text/plain
src/mame/machine/naomim4decoder.c svneol=native#text/plain
src/mame/machine/naomim4decoder.h svneol=native#text/plain
src/mame/machine/naomirom.c svneol=native#text/plain
src/mame/machine/naomirom.h svneol=native#text/plain
src/mame/machine/nb1413m3.c svneol=native#text/plain

View File

@ -804,6 +804,10 @@ void _class :: _name(address_map &map, const device_t &device) \
#define AM_IMPORT_FROM(_name) \
ADDRESS_MAP_NAME(_name)(map, device); \
// importing data from inherited address maps
#define AM_INHERIT_FROM(_name) \
_name(map, device); \
// address ranges
#define AM_RANGE(_start, _end) \

View File

@ -362,7 +362,7 @@ Thanks to Alex, Mr Mudkips, and Philip Burke for this info.
#include "emu.h"
#include "cpu/i386/i386.h"
#include "machine/pci.h"
#include "includes/naomibd.h"
#include "machine/naomigd.h"
#include "debug/debugcon.h"
#include "debug/debugcmd.h"
@ -661,7 +661,7 @@ static MACHINE_CONFIG_START( chihiro_base, driver_device )
MACHINE_CONFIG_END
static MACHINE_CONFIG_DERIVED( chihirogd, chihiro_base )
MCFG_NAOMI_DIMM_BOARD_ADD("rom_board", "gdrom", NULL, 512, "picreturn")
MCFG_NAOMI_GDROM_BOARD_ADD("rom_board", "gdrom", "picreturn", NULL, "maincpu", NULL)
MACHINE_CONFIG_END
#define ROM_LOAD16_WORD_SWAP_BIOS(bios,name,offset,length,hash) \

File diff suppressed because it is too large Load Diff

View File

@ -401,7 +401,7 @@ Notes:
#include "emu.h"
#include "cpu/powerpc/ppc.h"
#include "includes/naomibd.h"
#include "machine/naomigd.h"
static ADDRESS_MAP_START( gc_map, AS_PROGRAM, 32 )
AM_RANGE(0x7fe00000, 0x7fffffff) AM_ROM AM_REGION("maincpu", 0) AM_SHARE("share2") /* Program ROM */
@ -443,7 +443,7 @@ static MACHINE_CONFIG_START( triforce_base, driver_device )
MACHINE_CONFIG_END
static MACHINE_CONFIG_DERIVED( triforcegd, triforce_base )
MCFG_NAOMI_DIMM_BOARD_ADD("rom_board", "gdrom", NULL, 256, "picreturn")
MCFG_NAOMI_GDROM_BOARD_ADD("rom_board", "gdrom", "picreturn", NULL, "maincpu", NULL)
MACHINE_CONFIG_END
#define ROM_LOAD16_WORD_SWAP_BIOS(bios,name,offset,length,hash) \

View File

@ -44,3 +44,5 @@ extern UINT64 *naomi_ram64;
extern int jvsboard_type;
extern UINT16 actel_id;
void naomi_g1_irq(running_machine &machine);

View File

@ -1,101 +0,0 @@
/*************************************************************************
Naomi plug-in board
driver by Samuele Zannoli
**************************************************************************/
#include "devlegcy.h"
/***************************************************************************
CONSTANTS
***************************************************************************/
/* enumeration specifying which model of board we are emulating */
enum
{
ROM_BOARD,
DIMM_BOARD,
AW_ROM_BOARD,
MAX_NAOMIBD_TYPES
};
/***************************************************************************
TYPE DEFINITIONS
***************************************************************************/
typedef void (*naomibd_signal_func)(device_t *device, int signal, int state);
typedef struct _naomibd_config naomibd_config;
struct _naomibd_config
{
int type;
int size;
const char * regiontag;
const char * gdromregiontag;
const char * picregiontag;
naomibd_signal_func signal;
};
/***************************************************************************
DEVICE CONFIGURATION MACROS
***************************************************************************/
#define MCFG_NAOMIBD_ADD(_tag, _type) \
MCFG_DEVICE_ADD(_tag, NAOMI_BOARD, 0) \
MCFG_DEVICE_CONFIG_DATA32(naomibd_config, type, _type)
#define MCFG_NAOMI_ROM_BOARD_ADD(_tag, _region) \
MCFG_NAOMIBD_ADD(_tag, ROM_BOARD) \
MCFG_NAOMIBD_REGION(_region)
#define MCFG_AW_ROM_BOARD_ADD(_tag, _region) \
MCFG_NAOMIBD_ADD(_tag, AW_ROM_BOARD) \
MCFG_NAOMIBD_REGION(_region)
#define MCFG_NAOMI_DIMM_BOARD_ADD(_tag, _gdrom, _callback, _sizemb, _pic) \
MCFG_NAOMIBD_ADD(_tag, DIMM_BOARD) \
MCFG_DEVICE_CONFIG_DATAPTR(naomibd_config, signal, _callback) \
MCFG_NAOMIBD_GDROM_REGION(_gdrom) \
MCFG_NAOMIBD_SIZE(_sizemb) \
MCFG_NAOMIBD_PIC_REGION(_pic)
#define MCFG_NAOMIBD_REGION(_region) \
MCFG_DEVICE_CONFIG_DATAPTR(naomibd_config, regiontag, _region)
#define MCFG_NAOMIBD_GDROM_REGION(_region) \
MCFG_DEVICE_CONFIG_DATAPTR(naomibd_config, gdromregiontag, _region)
#define MCFG_NAOMIBD_PIC_REGION(_region) \
MCFG_DEVICE_CONFIG_DATAPTR(naomibd_config, picregiontag, _region)
#define MCFG_NAOMIBD_SIZE(_sizemb) \
MCFG_DEVICE_CONFIG_DATA32(naomibd_config, size, _sizemb)
#define MCFG_NAOMIBD_MODIFY(_tag) \
MCFG_DEVICE_MODIFY(_tag)
/*#define MCFG_NAOMIBD_TMU_MEMORY(_tmu, _tmumem) \
MCFG_DEVICE_CONFIG_DATA32(naomibd_config, tmumem##_tmu, _tmumem)*/
/*----------- defined in machine/naomibd.c -----------*/
/***************************************************************************
FUNCTION PROTOTYPES
***************************************************************************/
int naomibd_get_type(device_t *device);
void *naomibd_get_memory(device_t *device, UINT32 length);
offs_t naomibd_get_dmaoffset(device_t *device);
READ64_DEVICE_HANDLER( naomibd_r );
WRITE64_DEVICE_HANDLER( naomibd_w );
/* ----- device interface ----- */
DECLARE_LEGACY_DEVICE(NAOMI_BOARD, naomibd);

View File

@ -0,0 +1,330 @@
#define ADDRESS_MAP_MODERN
#include "emu.h"
#include "awboard.h"
/*
Atomiswave ROM board specs from Cah4e3 @ http://cah4e3.wordpress.com/2009/07/26/some-atomiswave-info/
AW_EPR_OFFSETL Register addres: 0x5f7000
+-------------------------------------------------------------------------------+
| bit15-0 |
+-------------------------------------------------------------------------------+
| EPR data offset low word |
+-------------------------------------------------------------------------------+
AW_EPR_OFFSETH Register addres: 0x5f7004
+-------------------------------------------------------------------------------+
| bit15-0 |
+-------------------------------------------------------------------------------+
| EPR data offset hi word |
+-------------------------------------------------------------------------------+
Both low and high words of 32-bit offset from start of EPR-ROM area. Used for
reading header and program code data, cannot be used for reading MPR-ROMs data.
AW_MPR_RECORD_INDEX Register addres: 0x5f700c
+-------------------------------------------------------------------------------+
| bit15-0 |
+-------------------------------------------------------------------------------+
| File system record index |
+-------------------------------------------------------------------------------+
This register contains index of MPR-ROM file system record (64-bytes in size) to
read throught DMA. Internal DMA offset register is assigned as AW_MPR_RECORD_INDEX<<6
from start of MPR-ROM area. Size of DMA transaction not limited, it is possible
to read any number of records or just part of it.
AW_MPR_FIRST_FILE_INDEX Register addres: 0x5f7010
+-------------------------------------------------------------------------------+
| bit15-0 |
+-------------------------------------------------------------------------------+
| First file record index |
+-------------------------------------------------------------------------------+
This register assign for internal cart circuit index of record in MPR-ROM file
system sub-area that contain information about first file of MPR-ROM files
sub-area. Internal circuit using this record to read absolute first file offset
from start of MPR-ROM area and calculate normal offset for each other file
requested, since MPR-ROM file data sub-area can be assighed only with relative
offsets from start of such sub-area.
AW_MPR_FILE_OFFSETL Register addres: 0x5f7014
+-------------------------------------------------------------------------------+
| bit15-0 |
+-------------------------------------------------------------------------------+
| MPR file offset low word |
+-------------------------------------------------------------------------------+
AW_MPR_FILE_OFFSETH Register addres: 0x5f7018
+-------------------------------------------------------------------------------+
| bit15-0 |
+-------------------------------------------------------------------------------+
| MPR file offset hi word |
+-------------------------------------------------------------------------------+
Both low and high words of 32-bit relative offset from start of MPR-ROM files
sub-area. Used by internal circuit to calculate absolute offset using data
from AW_MPR_FIRST_FILE_INDEX register. Cannot be used for reading EPR-ROM
data nor even MPR-ROM file system sub-area data.
In short:
EPR-ROM
+--------------+ 0x00000000
| |
| HEADER +- AW_EPR_OFFSET << 1
| |
+--------------+
| |
| CODE +- AW_EPR_OFFSET << 1
| |
| |
+--------------+ 0x007fffff
MPR-ROMS
+--------------+ 0x00000000
| FS_HEADER |
| FS_RECORD[1] +- (AW_MPR_RECORD_INDEX << 6)
| FS_RECORD[2] |
| FS_RECORD[3] +- (AW_MPR_FIRST_FILE_INDEX << 6)
| ... |
| FS_RECORD[N] |
+--------------+- FS_RECORD[AW_MPR_FIRST_FILE_INDEX].FILE_ABS_OFFSET
| FILE_0 |
| FILE_1 +- (AW_MPR_FILE_OFFSET << 1) + FS_RECORD[AW_MPR_FIRST_FILE_INDEX].FILE_ABS_OFFSET
| ... |
| FILE_N |
+--------------+ 0x07ffffff
*/
const device_type AW_ROM_BOARD = &device_creator<aw_rom_board>;
DEVICE_ADDRESS_MAP_START(submap, 16, aw_rom_board)
AM_RANGE(0x00, 0x01) AM_WRITE(epr_offsetl_w)
AM_RANGE(0x02, 0x03) AM_WRITE(epr_offseth_w)
AM_RANGE(0x06, 0x07) AM_WRITE(mpr_record_index_w)
AM_RANGE(0x08, 0x09) AM_WRITE(mpr_first_file_index_w)
AM_RANGE(0x0a, 0x0b) AM_WRITE(mpr_file_offsetl_w)
AM_RANGE(0x0c, 0x0d) AM_WRITE(mpr_file_offseth_w)
ADDRESS_MAP_END
aw_rom_board::aw_rom_board(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: naomi_g1_device(mconfig, AW_ROM_BOARD, "AW-ROM-BOARD", tag, owner, clock)
{
region_is_decrypted = false;
keyregion = 0;
}
void aw_rom_board::static_set_keyregion(device_t &device, const char *_keyregion)
{
aw_rom_board &dev = downcast<aw_rom_board &>(device);
dev.keyregion = _keyregion;
}
/*
We are using 20 bits keys with the following subfields' structure:
bits 0-15 is a 16-bits XOR
bits 17-16 is a index to the sboxes table
bits 19-18 is a index to the permutation table
These subfields could be differing from the "real" ones in the following ways:
- Every one of the index subfields could be suffering an arbitrary bitswap and XOR
- The 16-bits-XOR subfield could suffer an arbitrary XOR which could depend on the 4 index bits (that is: a different XOR per every index combination)
- Of course, the way in which we are mixing 3 subfields in one only key is arbitrary too.
The keys are stored as 32-bits big-endian values in a file.
*/
const int aw_rom_board::permutation_table[4][16] =
{
{8,10,1,3,7,4,11,2,5,15,6,0,12,13,9,14},
{4,5,9,6,1,13,7,11,10,0,14,12,8,15,2,3},
{12,7,11,2,0,5,15,6,1,8,14,4,9,13,3,10},
{14,1,11,15,7,3,8,13,0,4,2,12,6,10,5,9}
};
const aw_rom_board::sbox_set aw_rom_board::sboxes_table[4] =
{
{
{4,12,8,14,16,30,31,0,23,29,24,21,11,22,27,5,3,20,18,26,10,7,17,1,28,6,15,13,2,9,25,19},
{13,1,0,9,5,12,4,14,3,15,2,10,11,6,8,7},
{7,13,4,6,5,9,3,2,0,15,12,10,8,11,1,14},
{4,0,1,2,5,7,3,6}
},
{
{3,0,14,17,10,15,31,20,13,2,29,28,9,18,25,27,6,19,30,22,7,12,1,16,23,11,24,4,8,26,21,5},
{2,10,6,9,11,13,4,5,3,15,7,14,12,1,0,8},
{1,13,11,3,8,7,9,10,12,15,4,14,0,5,6,2},
{6,5,0,3,7,1,4,2}
},
{
{9,15,28,7,13,24,2,23,21,1,22,16,18,8,17,31,27,6,30,12,4,20,5,19,0,25,3,29,10,14,11,26},
{5,2,13,11,8,6,12,1,4,3,0,10,14,15,7,9},
{11,6,10,0,12,1,8,14,2,9,13,3,7,4,15,5},
{1,5,6,2,4,7,3,0}
},
{
{17,3,31,2,28,10,9,29,6,25,24,8,13,1,19,15,22,0,14,20,16,7,21,4,18,26,27,5,12,23,11,30},
{4,8,11,15,3,14,7,12,1,0,9,5,6,13,2,10},
{14,0,9,11,4,1,7,5,13,6,8,12,2,3,10,15},
{2,1,0,5,4,6,7,3}
},
};
UINT16 aw_rom_board::decrypt(UINT16 cipherText, UINT32 address, const UINT32 key)
{
UINT8 b0,b1,b2,b3;
UINT16 aux;
const int* pbox = permutation_table[key>>18];
const sbox_set* ss = &sboxes_table[(key>>16)&3];
aux = BITSWAP16(cipherText,
pbox[15],pbox[14],pbox[13],pbox[12],pbox[11],pbox[10],pbox[9],pbox[8],
pbox[7],pbox[6],pbox[5],pbox[4],pbox[3],pbox[2],pbox[1],pbox[0]);
aux = aux ^ BITSWAP16(address >> 1, 13,5,2, 14,10,9,4, 15,11,6,1, 12,8,7,3,0);
b0 = aux&0x1f;
b1 = (aux>>5)&0xf;
b2 = (aux>>9)&0xf;
b3 = aux>>13;
b0 = ss->S0[b0];
b1 = ss->S1[b1];
b2 = ss->S2[b2];
b3 = ss->S3[b3];
return ((b3<<13)|(b2<<9)|(b1<<5)|b0)^(key&0xffff);
}
void aw_rom_board::decrypt_region()
{
if(region_is_decrypted)
return;
region_is_decrypted = true;
if(!m_region)
throw emu_fatalerror("AW-ROM-BOARD: region %s is missing\n", tag());
if(!keyregion)
return;
const memory_region *kr = machine().region(keyregion);
if(!kr)
return;
if(kr->bytes() != 4)
throw emu_fatalerror("AW-ROM-BOARD: key region %s has incorrect size (%d, expected 4)\n", keyregion, kr->bytes());
const UINT8 *krp = kr->base();
UINT32 key = (krp[0] << 24) | (krp[1] << 16) | (krp[2] << 8) | krp[3];
UINT16 *src = (UINT16 *)m_region->base();
UINT32 rom_size = m_region->bytes();
for(UINT32 i=0; i<rom_size/2; i++)
src[i] = decrypt(src[i], i*2, key);
}
void aw_rom_board::device_start()
{
naomi_g1_device::device_start();
decrypt_region();
save_item(NAME(epr_offset));
save_item(NAME(mpr_record_index));
save_item(NAME(mpr_first_file_index));
save_item(NAME(mpr_file_offset));
save_item(NAME(dma_offset));
save_item(NAME(dma_limit));
}
void aw_rom_board::device_reset()
{
naomi_g1_device::device_reset();
epr_offset = 0;
mpr_record_index = 0;
mpr_first_file_index = 0;
mpr_file_offset = 0;
dma_offset = 0;
dma_limit = 0;
}
WRITE16_MEMBER(aw_rom_board::epr_offsetl_w)
{
epr_offset = (epr_offset & 0xffff0000) | data;
recalc_dma_offset(EPR);
}
WRITE16_MEMBER(aw_rom_board::epr_offseth_w)
{
epr_offset = (epr_offset & 0x0000ffff) | (data << 16);
recalc_dma_offset(EPR);
}
WRITE16_MEMBER(aw_rom_board::mpr_record_index_w)
{
mpr_record_index = data;
recalc_dma_offset(MPR_RECORD);
}
WRITE16_MEMBER(aw_rom_board::mpr_first_file_index_w)
{
mpr_first_file_index = data;
recalc_dma_offset(MPR_FILE);
}
WRITE16_MEMBER(aw_rom_board::mpr_file_offsetl_w)
{
mpr_file_offset = (mpr_file_offset & 0xffff0000) | data;
recalc_dma_offset(MPR_FILE);
}
WRITE16_MEMBER(aw_rom_board::mpr_file_offseth_w)
{
mpr_file_offset = (mpr_file_offset & 0x0000ffff) | (data << 16);
recalc_dma_offset(MPR_FILE);
}
void aw_rom_board::recalc_dma_offset(int mode)
{
switch(mode) {
case EPR:
dma_offset = epr_offset * 2;
dma_limit = 0x1000000;
break;
case MPR_RECORD:
dma_offset = 0x1000000 + mpr_record_index * 0x40;
dma_limit = m_region->bytes();
break;
case MPR_FILE: {
const UINT8 *entry = m_region->base() + 0x1000000 + mpr_first_file_index * 0x40;
dma_offset = 0x1000000 + (entry[8] | (entry[9] << 8) | (entry[10] << 16) | (entry[11] << 24)) + mpr_file_offset*2;
dma_limit = m_region->bytes();
break;
}
}
}
void aw_rom_board::dma_get_position(UINT8 *&base, UINT32 &limit, bool to_mainram)
{
if(!to_mainram) {
limit = 0;
base = 0;
return;
}
limit = dma_limit - dma_offset;
base = m_region->base() + dma_offset;
}
void aw_rom_board::dma_advance(UINT32 size)
{
dma_offset += size;
}

View File

@ -0,0 +1,61 @@
#ifndef _AWBOARD_H_
#define _AWBOARD_H_
#include "naomig1.h"
#define MCFG_AW_ROM_BOARD_ADD(_tag, _keyregion, _maincpu_tag, _irq_cb) \
MCFG_NAOMI_G1_ADD(_tag, AW_ROM_BOARD, _maincpu_tag, _irq_cb) \
aw_rom_board::static_set_keyregion(*device, _keyregion);
class aw_rom_board : public naomi_g1_device
{
public:
aw_rom_board(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
static void static_set_keyregion(device_t &device, const char *_keyregion);
DECLARE_ADDRESS_MAP(submap, 16);
DECLARE_WRITE16_MEMBER(epr_offsetl_w); // 5f7000
DECLARE_WRITE16_MEMBER(epr_offseth_w); // 5f7004
DECLARE_WRITE16_MEMBER(mpr_record_index_w); // 5f700c
DECLARE_WRITE16_MEMBER(mpr_first_file_index_w); // 5f7010
DECLARE_WRITE16_MEMBER(mpr_file_offsetl_w); // 5f7014
DECLARE_WRITE16_MEMBER(mpr_file_offseth_w); // 5f7018
protected:
virtual void device_start();
virtual void device_reset();
virtual void dma_get_position(UINT8 *&base, UINT32 &limit, bool to_mainram);
virtual void dma_advance(UINT32 size);
private:
enum { EPR, MPR_RECORD, MPR_FILE };
const char *keyregion;
bool region_is_decrypted;
UINT32 epr_offset, mpr_file_offset;
UINT16 mpr_record_index, mpr_first_file_index;
UINT32 dma_offset, dma_limit;
struct sbox_set {
UINT8 S0[32];
UINT8 S1[16];
UINT8 S2[16];
UINT8 S3[8];
};
static const int permutation_table[4][16];
static const sbox_set sboxes_table[4];
static UINT16 decrypt(UINT16 cipherText, UINT32 address, const UINT32 key);
void decrypt_region();
void recalc_dma_offset(int mode);
};
extern const device_type AW_ROM_BOARD;
#endif

View File

@ -9,7 +9,6 @@
#include "includes/dc.h"
#include "cpu/sh4/sh4.h"
#include "sound/aica.h"
#include "includes/naomibd.h"
#include "includes/naomi.h"
#include "machine/mie.h"
@ -120,9 +119,8 @@ static TIMER_CALLBACK( pvr_dma_irq )
dc_update_interrupt_status(machine);
}
static TIMER_CALLBACK( gdrom_dma_irq )
void naomi_g1_irq(running_machine &machine)
{
g1bus_regs[SB_GDST] = 0;
dc_sysctrl_regs[SB_ISTNRM] |= IST_DMA_GDROM;
dc_update_interrupt_status(machine);
}
@ -503,67 +501,6 @@ WRITE64_HANDLER( dc_gdrom_w )
mame_printf_verbose("GDROM: [%08x=%x]write %" I64FMT "x to %x, mask %" I64FMT "x\n", 0x5f7000+off*4, dat, data, offset, mem_mask);
}
READ64_HANDLER( dc_g1_ctrl_r )
{
int reg;
UINT64 shift;
reg = decode_reg32_64(space->machine(), offset, mem_mask, &shift);
mame_printf_verbose("G1CTRL: Unmapped read %08x\n", 0x5f7400+reg*4);
return (UINT64)g1bus_regs[reg] << shift;
}
WRITE64_HANDLER( dc_g1_ctrl_w )
{
int reg;
UINT64 shift;
UINT32 old,dat;
struct sh4_ddt_dma ddtdata;
UINT8 *ROM;
UINT32 dmaoffset;
reg = decode_reg32_64(space->machine(), offset, mem_mask, &shift);
dat = (UINT32)(data >> shift);
old = g1bus_regs[reg];
g1bus_regs[reg] = dat; // 5f7400+reg*4=dat
mame_printf_verbose("G1CTRL: [%08x=%x] write %" I64FMT "x to %x, mask %" I64FMT "x\n", 0x5f7400+reg*4, dat, data, offset, mem_mask);
switch (reg)
{
case SB_GDST:
g1bus_regs[SB_GDST] = old;
if (((old & 1) == 0) && (dat & 1) && g1bus_regs[SB_GDEN] == 1) // 0 -> 1
{
if (g1bus_regs[SB_GDDIR] == 0)
{
printf("G1CTRL: unsupported transfer\n");
return;
}
g1bus_regs[SB_GDST] = dat & 1;
// printf("Cart DMA to %x len %x (PC %x)\n", g1bus_regs[SB_GDSTAR], g1bus_regs[SB_GDLEN], cpu_get_pc(&space->device()));
ROM = (UINT8 *)naomibd_get_memory(space->machine().device("rom_board"), g1bus_regs[SB_GDLEN]);
dmaoffset = naomibd_get_dmaoffset(space->machine().device("rom_board"));
ddtdata.destination=g1bus_regs[SB_GDSTAR]; // destination address
ddtdata.length=g1bus_regs[SB_GDLEN] >> 5; // words to transfer
/* data in the lower 5 bits makes the length size to round by 32 bytes, this'll be needed by Virtua Tennis to boot (according to Deunan) */
if(g1bus_regs[SB_GDLEN] & 0x1c)
ddtdata.length++;
ddtdata.size=32; // bytes per word
ddtdata.buffer=ROM+dmaoffset; // buffer address
ddtdata.direction=1; // 0 source to buffer, 1 buffer to destination
ddtdata.channel= -1; // not used
ddtdata.mode= -1; // copy from/to buffer
mame_printf_verbose("G1CTRL: transfer %x from ROM %08x to sdram %08x\n", g1bus_regs[SB_GDLEN], dmaoffset, g1bus_regs[SB_GDSTAR]);
sh4_dma_ddt(space->machine().device("maincpu"), &ddtdata);
/* Note: KOF Neowave definitely wants this to be delayed (!) */
/* FIXME: timing of this */
space->machine().scheduler().timer_set(attotime::from_usec(500), FUNC(gdrom_dma_irq));
}
break;
}
}
READ64_HANDLER( dc_g2_ctrl_r )
{
int reg;

View File

@ -1,383 +0,0 @@
/* DES decryption, used by GD-ROM based titles (Naomi etc.) */
#include "emu.h"
#include "includes/naomi.h"
static UINT32 des_subkeys[32];
static const UINT32 DES_LEFTSWAP[] =
{
0x00000000, 0x00000001, 0x00000100, 0x00000101, 0x00010000, 0x00010001, 0x00010100, 0x00010101,
0x01000000, 0x01000001, 0x01000100, 0x01000101, 0x01010000, 0x01010001, 0x01010100, 0x01010101
};
static const UINT32 DES_RIGHTSWAP[] =
{
0x00000000, 0x01000000, 0x00010000, 0x01010000, 0x00000100, 0x01000100, 0x00010100, 0x01010100,
0x00000001, 0x01000001, 0x00010001, 0x01010001, 0x00000101, 0x01000101, 0x00010101, 0x01010101,
};
static const UINT32 DES_SBOX1[] =
{
0x00808200, 0x00000000, 0x00008000, 0x00808202, 0x00808002, 0x00008202, 0x00000002, 0x00008000,
0x00000200, 0x00808200, 0x00808202, 0x00000200, 0x00800202, 0x00808002, 0x00800000, 0x00000002,
0x00000202, 0x00800200, 0x00800200, 0x00008200, 0x00008200, 0x00808000, 0x00808000, 0x00800202,
0x00008002, 0x00800002, 0x00800002, 0x00008002, 0x00000000, 0x00000202, 0x00008202, 0x00800000,
0x00008000, 0x00808202, 0x00000002, 0x00808000, 0x00808200, 0x00800000, 0x00800000, 0x00000200,
0x00808002, 0x00008000, 0x00008200, 0x00800002, 0x00000200, 0x00000002, 0x00800202, 0x00008202,
0x00808202, 0x00008002, 0x00808000, 0x00800202, 0x00800002, 0x00000202, 0x00008202, 0x00808200,
0x00000202, 0x00800200, 0x00800200, 0x00000000, 0x00008002, 0x00008200, 0x00000000, 0x00808002
};
static const UINT32 DES_SBOX2[] =
{
0x40084010, 0x40004000, 0x00004000, 0x00084010, 0x00080000, 0x00000010, 0x40080010, 0x40004010,
0x40000010, 0x40084010, 0x40084000, 0x40000000, 0x40004000, 0x00080000, 0x00000010, 0x40080010,
0x00084000, 0x00080010, 0x40004010, 0x00000000, 0x40000000, 0x00004000, 0x00084010, 0x40080000,
0x00080010, 0x40000010, 0x00000000, 0x00084000, 0x00004010, 0x40084000, 0x40080000, 0x00004010,
0x00000000, 0x00084010, 0x40080010, 0x00080000, 0x40004010, 0x40080000, 0x40084000, 0x00004000,
0x40080000, 0x40004000, 0x00000010, 0x40084010, 0x00084010, 0x00000010, 0x00004000, 0x40000000,
0x00004010, 0x40084000, 0x00080000, 0x40000010, 0x00080010, 0x40004010, 0x40000010, 0x00080010,
0x00084000, 0x00000000, 0x40004000, 0x00004010, 0x40000000, 0x40080010, 0x40084010, 0x00084000
};
static const UINT32 DES_SBOX3[] =
{
0x00000104, 0x04010100, 0x00000000, 0x04010004, 0x04000100, 0x00000000, 0x00010104, 0x04000100,
0x00010004, 0x04000004, 0x04000004, 0x00010000, 0x04010104, 0x00010004, 0x04010000, 0x00000104,
0x04000000, 0x00000004, 0x04010100, 0x00000100, 0x00010100, 0x04010000, 0x04010004, 0x00010104,
0x04000104, 0x00010100, 0x00010000, 0x04000104, 0x00000004, 0x04010104, 0x00000100, 0x04000000,
0x04010100, 0x04000000, 0x00010004, 0x00000104, 0x00010000, 0x04010100, 0x04000100, 0x00000000,
0x00000100, 0x00010004, 0x04010104, 0x04000100, 0x04000004, 0x00000100, 0x00000000, 0x04010004,
0x04000104, 0x00010000, 0x04000000, 0x04010104, 0x00000004, 0x00010104, 0x00010100, 0x04000004,
0x04010000, 0x04000104, 0x00000104, 0x04010000, 0x00010104, 0x00000004, 0x04010004, 0x00010100
};
static const UINT32 DES_SBOX4[] =
{
0x80401000, 0x80001040, 0x80001040, 0x00000040, 0x00401040, 0x80400040, 0x80400000, 0x80001000,
0x00000000, 0x00401000, 0x00401000, 0x80401040, 0x80000040, 0x00000000, 0x00400040, 0x80400000,
0x80000000, 0x00001000, 0x00400000, 0x80401000, 0x00000040, 0x00400000, 0x80001000, 0x00001040,
0x80400040, 0x80000000, 0x00001040, 0x00400040, 0x00001000, 0x00401040, 0x80401040, 0x80000040,
0x00400040, 0x80400000, 0x00401000, 0x80401040, 0x80000040, 0x00000000, 0x00000000, 0x00401000,
0x00001040, 0x00400040, 0x80400040, 0x80000000, 0x80401000, 0x80001040, 0x80001040, 0x00000040,
0x80401040, 0x80000040, 0x80000000, 0x00001000, 0x80400000, 0x80001000, 0x00401040, 0x80400040,
0x80001000, 0x00001040, 0x00400000, 0x80401000, 0x00000040, 0x00400000, 0x00001000, 0x00401040
};
static const UINT32 DES_SBOX5[] =
{
0x00000080, 0x01040080, 0x01040000, 0x21000080, 0x00040000, 0x00000080, 0x20000000, 0x01040000,
0x20040080, 0x00040000, 0x01000080, 0x20040080, 0x21000080, 0x21040000, 0x00040080, 0x20000000,
0x01000000, 0x20040000, 0x20040000, 0x00000000, 0x20000080, 0x21040080, 0x21040080, 0x01000080,
0x21040000, 0x20000080, 0x00000000, 0x21000000, 0x01040080, 0x01000000, 0x21000000, 0x00040080,
0x00040000, 0x21000080, 0x00000080, 0x01000000, 0x20000000, 0x01040000, 0x21000080, 0x20040080,
0x01000080, 0x20000000, 0x21040000, 0x01040080, 0x20040080, 0x00000080, 0x01000000, 0x21040000,
0x21040080, 0x00040080, 0x21000000, 0x21040080, 0x01040000, 0x00000000, 0x20040000, 0x21000000,
0x00040080, 0x01000080, 0x20000080, 0x00040000, 0x00000000, 0x20040000, 0x01040080, 0x20000080
};
static const UINT32 DES_SBOX6[] =
{
0x10000008, 0x10200000, 0x00002000, 0x10202008, 0x10200000, 0x00000008, 0x10202008, 0x00200000,
0x10002000, 0x00202008, 0x00200000, 0x10000008, 0x00200008, 0x10002000, 0x10000000, 0x00002008,
0x00000000, 0x00200008, 0x10002008, 0x00002000, 0x00202000, 0x10002008, 0x00000008, 0x10200008,
0x10200008, 0x00000000, 0x00202008, 0x10202000, 0x00002008, 0x00202000, 0x10202000, 0x10000000,
0x10002000, 0x00000008, 0x10200008, 0x00202000, 0x10202008, 0x00200000, 0x00002008, 0x10000008,
0x00200000, 0x10002000, 0x10000000, 0x00002008, 0x10000008, 0x10202008, 0x00202000, 0x10200000,
0x00202008, 0x10202000, 0x00000000, 0x10200008, 0x00000008, 0x00002000, 0x10200000, 0x00202008,
0x00002000, 0x00200008, 0x10002008, 0x00000000, 0x10202000, 0x10000000, 0x00200008, 0x10002008
};
static const UINT32 DES_SBOX7[] =
{
0x00100000, 0x02100001, 0x02000401, 0x00000000, 0x00000400, 0x02000401, 0x00100401, 0x02100400,
0x02100401, 0x00100000, 0x00000000, 0x02000001, 0x00000001, 0x02000000, 0x02100001, 0x00000401,
0x02000400, 0x00100401, 0x00100001, 0x02000400, 0x02000001, 0x02100000, 0x02100400, 0x00100001,
0x02100000, 0x00000400, 0x00000401, 0x02100401, 0x00100400, 0x00000001, 0x02000000, 0x00100400,
0x02000000, 0x00100400, 0x00100000, 0x02000401, 0x02000401, 0x02100001, 0x02100001, 0x00000001,
0x00100001, 0x02000000, 0x02000400, 0x00100000, 0x02100400, 0x00000401, 0x00100401, 0x02100400,
0x00000401, 0x02000001, 0x02100401, 0x02100000, 0x00100400, 0x00000000, 0x00000001, 0x02100401,
0x00000000, 0x00100401, 0x02100000, 0x00000400, 0x02000001, 0x02000400, 0x00000400, 0x00100001
};
static const UINT32 DES_SBOX8[] =
{
0x08000820, 0x00000800, 0x00020000, 0x08020820, 0x08000000, 0x08000820, 0x00000020, 0x08000000,
0x00020020, 0x08020000, 0x08020820, 0x00020800, 0x08020800, 0x00020820, 0x00000800, 0x00000020,
0x08020000, 0x08000020, 0x08000800, 0x00000820, 0x00020800, 0x00020020, 0x08020020, 0x08020800,
0x00000820, 0x00000000, 0x00000000, 0x08020020, 0x08000020, 0x08000800, 0x00020820, 0x00020000,
0x00020820, 0x00020000, 0x08020800, 0x00000800, 0x00000020, 0x08020020, 0x00000800, 0x00020820,
0x08000800, 0x00000020, 0x08000020, 0x08020000, 0x08020020, 0x08000000, 0x00020000, 0x08000820,
0x00000000, 0x08020820, 0x00020020, 0x08000020, 0x08020000, 0x08000800, 0x08000820, 0x00000000,
0x08020820, 0x00020800, 0x00020800, 0x00000820, 0x00000820, 0x00020020, 0x08000000, 0x08020800
};
static const UINT32 DES_MASK_TABLE[] =
{
0x24000000, 0x10000000, 0x08000000, 0x02080000, 0x01000000,
0x00200000, 0x00100000, 0x00040000, 0x00020000, 0x00010000,
0x00002000, 0x00001000, 0x00000800, 0x00000400, 0x00000200,
0x00000100, 0x00000020, 0x00000010, 0x00000008, 0x00000004,
0x00000002, 0x00000001, 0x20000000, 0x10000000, 0x08000000,
0x04000000, 0x02000000, 0x01000000, 0x00200000, 0x00100000,
0x00080000, 0x00040000, 0x00020000, 0x00010000, 0x00002000,
0x00001000, 0x00000808, 0x00000400, 0x00000200, 0x00000100,
0x00000020, 0x00000011, 0x00000004, 0x00000002
};
static const UINT8 DES_ROTATE_TABLE[16] =
{
1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
};
INLINE void permutate(UINT32*a, UINT32*b, UINT32 m, int shift)
{
UINT32 temp;
temp = ((*a>>shift) ^ *b) & m;
*a ^= temp<<shift;
*b ^= temp;
}
static void des_generate_subkeys(const UINT64 key, UINT32 *subkeys)
{
UINT32 l, r;
int round;
l = (key & 0xffffffff00000000ULL)>>32;
r = (key & 0x00000000ffffffffULL)>>0;;
permutate(&r, &l, 0x0f0f0f0f, 4);
permutate(&r, &l, 0x10101010, 0);
l = (DES_LEFTSWAP[(l >> 0) & 0xf] << 3) |
(DES_LEFTSWAP[(l >> 8) & 0xf] << 2) |
(DES_LEFTSWAP[(l >> 16) & 0xf] << 1) |
(DES_LEFTSWAP[(l >> 24) & 0xf] << 0) |
(DES_LEFTSWAP[(l >> 5) & 0xf] << 7) |
(DES_LEFTSWAP[(l >> 13) & 0xf] << 6) |
(DES_LEFTSWAP[(l >> 21) & 0xf] << 5) |
(DES_LEFTSWAP[(l >> 29) & 0xf] << 4);
r = (DES_RIGHTSWAP[(r >> 1) & 0xf] << 3) |
(DES_RIGHTSWAP[(r >> 9) & 0xf] << 2) |
(DES_RIGHTSWAP[(r >> 17) & 0xf] << 1) |
(DES_RIGHTSWAP[(r >> 25) & 0xf] << 0) |
(DES_RIGHTSWAP[(r >> 4) & 0xf] << 7) |
(DES_RIGHTSWAP[(r >> 12) & 0xf] << 6) |
(DES_RIGHTSWAP[(r >> 20) & 0xf] << 5) |
(DES_RIGHTSWAP[(r >> 28) & 0xf] << 4);
l &= 0x0fffffff;
r &= 0x0fffffff;
for (round = 0; round < 16; round++)
{
l = ((l << DES_ROTATE_TABLE[round]) | (l >> (28 - DES_ROTATE_TABLE[round]))) & 0x0fffffff;
r = ((r << DES_ROTATE_TABLE[round]) | (r >> (28 - DES_ROTATE_TABLE[round]))) & 0x0fffffff;
subkeys[round*2] =
((l << 4) & DES_MASK_TABLE[0]) |
((l << 28) & DES_MASK_TABLE[1]) |
((l << 14) & DES_MASK_TABLE[2]) |
((l << 18) & DES_MASK_TABLE[3]) |
((l << 6) & DES_MASK_TABLE[4]) |
((l << 9) & DES_MASK_TABLE[5]) |
((l >> 1) & DES_MASK_TABLE[6]) |
((l << 10) & DES_MASK_TABLE[7]) |
((l << 2) & DES_MASK_TABLE[8]) |
((l >> 10) & DES_MASK_TABLE[9]) |
((r >> 13) & DES_MASK_TABLE[10])|
((r >> 4) & DES_MASK_TABLE[11])|
((r << 6) & DES_MASK_TABLE[12])|
((r >> 1) & DES_MASK_TABLE[13])|
((r >> 14) & DES_MASK_TABLE[14])|
((r >> 0) & DES_MASK_TABLE[15])|
((r >> 5) & DES_MASK_TABLE[16])|
((r >> 10) & DES_MASK_TABLE[17])|
((r >> 3) & DES_MASK_TABLE[18])|
((r >> 18) & DES_MASK_TABLE[19])|
((r >> 26) & DES_MASK_TABLE[20])|
((r >> 24) & DES_MASK_TABLE[21]);
subkeys[round*2+1] =
((l << 15) & DES_MASK_TABLE[22])|
((l << 17) & DES_MASK_TABLE[23])|
((l << 10) & DES_MASK_TABLE[24])|
((l << 22) & DES_MASK_TABLE[25])|
((l >> 2) & DES_MASK_TABLE[26])|
((l << 1) & DES_MASK_TABLE[27])|
((l << 16) & DES_MASK_TABLE[28])|
((l << 11) & DES_MASK_TABLE[29])|
((l << 3) & DES_MASK_TABLE[30])|
((l >> 6) & DES_MASK_TABLE[31])|
((l << 15) & DES_MASK_TABLE[32])|
((l >> 4) & DES_MASK_TABLE[33])|
((r >> 2) & DES_MASK_TABLE[34])|
((r << 8) & DES_MASK_TABLE[35])|
((r >> 14) & DES_MASK_TABLE[36])|
((r >> 9) & DES_MASK_TABLE[37])|
((r >> 0) & DES_MASK_TABLE[38])|
((r << 7) & DES_MASK_TABLE[39])|
((r >> 7) & DES_MASK_TABLE[40])|
((r >> 3) & DES_MASK_TABLE[41])|
((r << 2) & DES_MASK_TABLE[42])|
((r >> 21) & DES_MASK_TABLE[43]);
}
}
static UINT64 des_encrypt_decrypt(int decrypt, UINT64 ret)
{
UINT32 l;
UINT32 r;
int i;
int subkey;
r = (ret & 0x00000000ffffffffULL) >> 0;
l = (ret & 0xffffffff00000000ULL) >> 32;
permutate(&l, &r, 0x0f0f0f0f, 4);
permutate(&l, &r, 0x0000ffff, 16);
permutate(&r, &l, 0x33333333, 2);
permutate(&r, &l, 0x00ff00ff, 8);
permutate(&l, &r, 0x55555555, 1);
if (decrypt) subkey = 30;
else subkey = 0;
for (i = 0; i < 32 ; i+=4)
{
UINT32 temp;
temp = ((r<<1) | (r>>31)) ^ des_subkeys[subkey];
l ^= DES_SBOX8[ (temp>>0) & 0x3f ];
l ^= DES_SBOX6[ (temp>>8) & 0x3f ];
l ^= DES_SBOX4[ (temp>>16) & 0x3f ];
l ^= DES_SBOX2[ (temp>>24) & 0x3f ];
subkey++;
temp = ((r>>3) | (r<<29)) ^ des_subkeys[subkey];
l ^= DES_SBOX7[ (temp>>0) & 0x3f ];
l ^= DES_SBOX5[ (temp>>8) & 0x3f ];
l ^= DES_SBOX3[ (temp>>16) & 0x3f ];
l ^= DES_SBOX1[ (temp>>24) & 0x3f ];
subkey++;
if (decrypt) subkey-=4;
temp = ((l<<1) | (l>>31)) ^ des_subkeys[subkey];
r ^= DES_SBOX8[ (temp>>0) & 0x3f ];
r ^= DES_SBOX6[ (temp>>8) & 0x3f ];
r ^= DES_SBOX4[ (temp>>16) & 0x3f ];
r ^= DES_SBOX2[ (temp>>24) & 0x3f ];
subkey++;
temp = ((l>>3) | (l<<29)) ^ des_subkeys[subkey];
r ^= DES_SBOX7[ (temp>>0) & 0x3f ];
r ^= DES_SBOX5[ (temp>>8) & 0x3f ];
r ^= DES_SBOX3[ (temp>>16) & 0x3f ];
r ^= DES_SBOX1[ (temp>>24) & 0x3f ];
subkey++;
if (decrypt) subkey-=4;
}
permutate(&r, &l, 0x55555555, 1);
permutate(&l, &r, 0x00ff00ff, 8);
permutate(&l, &r, 0x33333333, 2);
permutate(&r, &l, 0x0000ffff, 16);
permutate(&r, &l, 0x0f0f0f0f, 4);
return ((UINT64)r << 32) | ((UINT64)l);
}
static UINT64 rev64(UINT64 src)
{
UINT64 ret;
ret = ((src & 0x00000000000000ffULL) << 56)
| ((src & 0x000000000000ff00ULL) << 40)
| ((src & 0x0000000000ff0000ULL) << 24)
| ((src & 0x00000000ff000000ULL) << 8 )
| ((src & 0x000000ff00000000ULL) >> 8 )
| ((src & 0x0000ff0000000000ULL) >> 24)
| ((src & 0x00ff000000000000ULL) >> 40)
| ((src & 0xff00000000000000ULL) >> 56);
return ret;
}
static UINT64 read_to_qword(UINT8* region)
{
int i;
UINT64 ret = 0;
for (i=0;i<8;i++)
{
UINT8 byte = region[i];
ret += (UINT64)byte << (56-(8*i));
}
return ret;
}
static void write_from_qword(UINT8* region, UINT64 qword)
{
int i;
for (i=0;i<8;i++)
{
region[i] = qword >> (56-(i*8));
}
}
void naomi_game_decrypt(running_machine& machine, UINT64 key, UINT8* region, int length)
{
int i;
des_generate_subkeys (rev64(key), des_subkeys);
#ifdef MAME_DEBUG
/* save the original file */
{
FILE *fp;
char filename[256];
sprintf(filename,"encrypted %s", machine.system().name);
fp=fopen(filename, "w+b");
if (fp)
{
fwrite(region, length, 1, fp);
fclose(fp);
}
}
#endif
for(i=0;i<length;i+=8)
{
UINT64 ret;
ret = read_to_qword(region+i);
ret = rev64(ret);
ret = des_encrypt_decrypt(1, ret);
ret = rev64(ret);
write_from_qword(region+i, ret);
}
#ifdef MAME_DEBUG
/* save the decrypted file */
{
FILE *fp;
char filename[256];
sprintf(filename,"decrypted %s", machine.system().name);
fp=fopen(filename, "w+b");
if (fp)
{
fwrite(region, length, 1, fp);
fclose(fp);
}
}
#endif
}

View File

@ -39,6 +39,7 @@ void maple_dc_device::register_port(int port, maple_device *device)
void maple_dc_device::device_start()
{
fprintf(stderr, "Device started\n");
cpu = machine().device<sh4_device>(maincpu_tag);
timer = timer_alloc(0);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,57 @@
#ifndef _NAOMIBD_H_
#define _NAOMIBD_H_
#include "naomig1.h"
#define MCFG_NAOMI_BOARD_ADD(_tag, type, _eeprom_tag, _maincpu_tag, _irq_cb) \
MCFG_NAOMI_G1_ADD(_tag, type, _maincpu_tag, _irq_cb) \
naomi_board::static_set_eeprom_tag(*device, _eeprom_tag);
class naomi_board : public naomi_g1_device
{
public:
naomi_board(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock);
static void static_set_eeprom_tag(device_t &device, const char *_eeprom_tag);
// Can be patched in the underlying class
virtual DECLARE_ADDRESS_MAP(submap, 16);
DECLARE_WRITE16_MEMBER(rom_offseth_w); // 5f7000
DECLARE_WRITE16_MEMBER(rom_offsetl_w); // 5f7004
DECLARE_READ16_MEMBER( rom_data_r); // 5f7008
DECLARE_WRITE16_MEMBER(rom_data_w); // 5f7008
DECLARE_WRITE16_MEMBER(dma_offseth_w); // 5f700c
DECLARE_WRITE16_MEMBER(dma_offsetl_w); // 5f7010
DECLARE_WRITE16_MEMBER(dma_count_w); // 5f7014
DECLARE_WRITE16_MEMBER(boardid_w); // 5f7078
DECLARE_READ16_MEMBER( boardid_r); // 5f707c
DECLARE_READ16_MEMBER( default_r);
protected:
virtual void device_start();
virtual void device_reset();
virtual void dma_get_position(UINT8 *&base, UINT32 &limit, bool to_mainram);
virtual void dma_advance(UINT32 size);
// To be defined in the underlying class
virtual void board_setup_address(UINT32 address, bool is_dma) = 0;
virtual void board_get_buffer(UINT8 *&base, UINT32 &limit) = 0;
virtual void board_advance(UINT32 size) = 0;
// To be optionally defined in the underlying class
virtual void board_write(offs_t offset, UINT16 data);
private:
UINT32 rom_offset, dma_offset, dma_cur_offset;
UINT16 dma_count;
bool pio_ready, dma_ready;
const char *eeprom_tag;
class x76f100_device *eeprom;
};
#endif

View File

@ -0,0 +1,257 @@
#define ADDRESS_MAP_MODERN
#include "emu.h"
#include "naomig1.h"
DEVICE_ADDRESS_MAP_START(amap, 32, naomi_g1_device)
AM_RANGE(0x04, 0x07) AM_READWRITE(sb_gdstar_r, sb_gdstar_w)
AM_RANGE(0x08, 0x0b) AM_READWRITE(sb_gdlen_r, sb_gdlen_w)
AM_RANGE(0x0c, 0x0f) AM_READWRITE(sb_gddir_r, sb_gddir_w)
AM_RANGE(0x14, 0x17) AM_READWRITE(sb_gden_r, sb_gden_w)
AM_RANGE(0x18, 0x1b) AM_READWRITE(sb_gdst_r, sb_gdst_w)
AM_RANGE(0x80, 0x83) AM_WRITE(sb_g1rrc_w)
AM_RANGE(0x84, 0x87) AM_WRITE(sb_g1rwc_w)
AM_RANGE(0x88, 0x8b) AM_WRITE(sb_g1frc_w)
AM_RANGE(0x8c, 0x8f) AM_WRITE(sb_g1fwc_w)
AM_RANGE(0x90, 0x93) AM_WRITE(sb_g1crc_w)
AM_RANGE(0x94, 0x97) AM_WRITE(sb_g1cwc_w)
AM_RANGE(0xa0, 0xa3) AM_WRITE(sb_g1gdrc_w)
AM_RANGE(0xa4, 0xa7) AM_WRITE(sb_g1gdwc_w)
AM_RANGE(0xb0, 0xb3) AM_READ(sb_g1sysm_r)
AM_RANGE(0xb4, 0xb7) AM_WRITE(sb_g1crdyc_w)
AM_RANGE(0xb8, 0xbb) AM_WRITE(sb_gdapro_w)
AM_RANGE(0xf4, 0xf7) AM_READ(sb_gdstard_r)
AM_RANGE(0xf8, 0xfb) AM_READ(sb_gdlend_r)
ADDRESS_MAP_END
naomi_g1_device::naomi_g1_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock)
: device_t(mconfig, type, name, tag, owner, clock)
{
cpu = 0;
}
void naomi_g1_device::static_set_maincpu_tag(device_t &device, const char *maincpu_tag)
{
naomi_g1_device &naomi_g1 = downcast<naomi_g1_device &>(device);
naomi_g1.maincpu_tag = maincpu_tag;
}
void naomi_g1_device::static_set_irq_cb(device_t &device, void (*irq_cb)(running_machine &))
{
naomi_g1_device &naomi_g1 = downcast<naomi_g1_device &>(device);
naomi_g1.irq_cb = irq_cb;
}
void naomi_g1_device::device_start()
{
cpu = machine().device<sh4_device>(maincpu_tag);
timer = timer_alloc(G1_TIMER_ID);
save_item(NAME(gdstar));
save_item(NAME(gdlen));
save_item(NAME(gddir));
save_item(NAME(gden));
save_item(NAME(gdst));
}
void naomi_g1_device::device_reset()
{
gdstar = 0;
gdlen = 0;
gddir = 0;
gden = 0;
gdst = 0;
}
void naomi_g1_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
timer.adjust(attotime::never);
if(!gdst)
return;
gdst = 0;
if(irq_cb)
irq_cb(machine());
}
READ32_MEMBER(naomi_g1_device::sb_gdstar_r)
{
return gdstar;
}
WRITE32_MEMBER(naomi_g1_device::sb_gdstar_w)
{
COMBINE_DATA(&gdstar);
logerror("G1: gdstar_w %08x @ %08x\n", data, mem_mask);
}
READ32_MEMBER(naomi_g1_device::sb_gdlen_r)
{
return gdlen;
}
WRITE32_MEMBER(naomi_g1_device::sb_gdlen_w)
{
COMBINE_DATA(&gdlen);
logerror("G1: gdlen_w %08x @ %08x\n", data, mem_mask);
}
READ32_MEMBER(naomi_g1_device::sb_gddir_r)
{
return gddir;
}
WRITE32_MEMBER(naomi_g1_device::sb_gddir_w)
{
COMBINE_DATA(&gddir);
gddir &= 1;
logerror("G1: gddir_w %08x @ %08x\n", data, mem_mask);
}
READ32_MEMBER(naomi_g1_device::sb_gden_r)
{
return gden;
}
WRITE32_MEMBER(naomi_g1_device::sb_gden_w)
{
COMBINE_DATA(&gden);
gden &= 1;
logerror("G1: gden_w %08x @ %08x\n", data, mem_mask);
}
READ32_MEMBER(naomi_g1_device::sb_gdst_r)
{
return gdst;
}
WRITE32_MEMBER(naomi_g1_device::sb_gdst_w)
{
UINT32 old = gdst;
COMBINE_DATA(&gdst);
gdst &= 1;
logerror("G1: gdst_w %08x @ %08x\n", data, mem_mask);
if(!old && gdst && gden) {
// DMA starts
UINT32 adr = gdstar;
UINT32 len = gdlen;
// Deunan says round up to 32, doc says complete with zeroes.
// Virtua Tennis requires one of the two to boot
// We'll go with DK for now.
//
// In any case, low bit is ignored
len = (len + 30) & ~30;
bool to_mainram = true;
while(len) {
UINT8 *base;
UINT32 limit = len;
dma_get_position(base, limit, to_mainram);
if(!limit)
break;
UINT32 tlen = limit > len ? len : limit;
dma(base, adr, tlen, to_mainram);
adr += tlen;
len -= tlen;
dma_advance(tlen);
}
while(len && to_mainram) {
unsigned char zero[32];
memset(zero, 0, sizeof(zero));
UINT32 tlen = len > 32 ? 32 : len;
dma(zero, adr, tlen, to_mainram);
adr += tlen;
len -= tlen;
}
timer->adjust(attotime::from_usec(500));
}
}
WRITE32_MEMBER(naomi_g1_device::sb_g1rrc_w)
{
logerror("G1: g1rrc_w %08x @ %08x\n", data, mem_mask);
}
WRITE32_MEMBER(naomi_g1_device::sb_g1rwc_w)
{
logerror("G1: g1rwc_w %08x @ %08x\n", data, mem_mask);
}
WRITE32_MEMBER(naomi_g1_device::sb_g1crc_w)
{
logerror("G1: g1crc_w %08x @ %08x\n", data, mem_mask);
}
WRITE32_MEMBER(naomi_g1_device::sb_g1cwc_w)
{
logerror("G1: g1cwc_w %08x @ %08x\n", data, mem_mask);
}
WRITE32_MEMBER(naomi_g1_device::sb_g1frc_w)
{
logerror("G1: g1frc_w %08x @ %08x\n", data, mem_mask);
}
WRITE32_MEMBER(naomi_g1_device::sb_g1fwc_w)
{
logerror("G1: g1fwc_w %08x @ %08x\n", data, mem_mask);
}
WRITE32_MEMBER(naomi_g1_device::sb_g1gdrc_w)
{
logerror("G1: g1gdrc_w %08x @ %08x\n", data, mem_mask);
}
WRITE32_MEMBER(naomi_g1_device::sb_g1gdwc_w)
{
logerror("G1: g1gdwc_w %08x @ %08x\n", data, mem_mask);
}
READ32_MEMBER(naomi_g1_device::sb_g1sysm_r)
{
logerror("G1: g1sysm_r @ %08x\n", mem_mask);
return 0;
}
WRITE32_MEMBER(naomi_g1_device::sb_g1crdyc_w)
{
logerror("G1: g1crdyc_w %08x @ %08x\n", data, mem_mask);
}
WRITE32_MEMBER(naomi_g1_device::sb_gdapro_w)
{
logerror("G1: gdapro_w %08x @ %08x\n", data, mem_mask);
}
READ32_MEMBER(naomi_g1_device::sb_gdstard_r)
{
logerror("G1: gdstard_r @ %08x\n", mem_mask);
return 0;
}
READ32_MEMBER(naomi_g1_device::sb_gdlend_r)
{
logerror("G1: gdlend_r @ %08x\n", mem_mask);
return 0;
}
void naomi_g1_device::dma(void *dma_ptr, UINT32 main_adr, UINT32 size, bool to_mainram)
{
sh4_ddt_dma ddt;
if(to_mainram)
ddt.destination = main_adr;
else
ddt.source = main_adr;
ddt.buffer = dma_ptr;
ddt.length = size >> 5;
ddt.size = 32;
ddt.direction = to_mainram;
ddt.channel = -1;
ddt.mode = -1;
sh4_dma_ddt(cpu, &ddt);
}

View File

@ -0,0 +1,67 @@
#ifndef _NAOMIG1_H_
#define _NAOMIG1_H_
#include "cpu/sh4/sh4.h"
#define MCFG_NAOMI_G1_ADD(_tag, type, _maincpu_tag, _irq_cb) \
MCFG_DEVICE_ADD(_tag, type, 0) \
naomi_g1_device::static_set_maincpu_tag(*device, _maincpu_tag); \
naomi_g1_device::static_set_irq_cb(*device, _irq_cb);
class naomi_g1_device : public device_t
{
public:
naomi_g1_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock);
static void static_set_maincpu_tag(device_t &device, const char *maincpu_tag);
static void static_set_irq_cb(device_t &device, void (*irq_cb)(running_machine &));
DECLARE_ADDRESS_MAP(amap, 32);
DECLARE_READ32_MEMBER(sb_gdstar_r); // 5f7404
DECLARE_WRITE32_MEMBER(sb_gdstar_w); // 5f7404
DECLARE_READ32_MEMBER(sb_gdlen_r); // 5f7408
DECLARE_WRITE32_MEMBER(sb_gdlen_w); // 5f7408
DECLARE_READ32_MEMBER(sb_gddir_r); // 5f740c
DECLARE_WRITE32_MEMBER(sb_gddir_w); // 5f740c
DECLARE_READ32_MEMBER(sb_gden_r); // 5f7414
DECLARE_WRITE32_MEMBER(sb_gden_w); // 5f7414
DECLARE_READ32_MEMBER(sb_gdst_r); // 5f7418
DECLARE_WRITE32_MEMBER(sb_gdst_w); // 5f7418
DECLARE_WRITE32_MEMBER(sb_g1rrc_w); // 5f7480
DECLARE_WRITE32_MEMBER(sb_g1rwc_w); // 5f7484
DECLARE_WRITE32_MEMBER(sb_g1frc_w); // 5f7488
DECLARE_WRITE32_MEMBER(sb_g1fwc_w); // 5f748c
DECLARE_WRITE32_MEMBER(sb_g1crc_w); // 5f7490
DECLARE_WRITE32_MEMBER(sb_g1cwc_w); // 5f7494
DECLARE_WRITE32_MEMBER(sb_g1gdrc_w); // 5f74a0
DECLARE_WRITE32_MEMBER(sb_g1gdwc_w); // 5f74a4
DECLARE_READ32_MEMBER(sb_g1sysm_r); // 5f74b0
DECLARE_WRITE32_MEMBER(sb_g1crdyc_w); // 5f74b4
DECLARE_WRITE32_MEMBER(sb_gdapro_w); // 5f74b8
DECLARE_READ32_MEMBER(sb_gdstard_r); // 5f74f4
DECLARE_READ32_MEMBER(sb_gdlend_r); // 5f74f8
protected:
enum { G1_TIMER_ID = 0x42 };
virtual void device_start();
virtual void device_reset();
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
virtual void dma_get_position(UINT8 *&base, UINT32 &limit, bool to_maincpu) = 0;
virtual void dma_advance(UINT32 size) = 0;
private:
UINT32 gdstar, gdlen, gddir, gden, gdst;
sh4_device *cpu;
const char *maincpu_tag;
emu_timer *timer;
void (*irq_cb)(running_machine &);
void dma(void *dma_ptr, UINT32 main_adr, UINT32 size, bool to_mainram);
};
#endif

View File

@ -0,0 +1,515 @@
#define ADDRESS_MAP_MODERN
#include "emu.h"
#include "naomigd.h"
#include "imagedev/chd_cd.h"
/*
Dimm board registers (add more information if you find it):
Name: Naomi Dimm Bd.
NAOMI_DIMM_COMMAND = 5f703c 14000014 (16 bit):
if bits all 1 no dimm board present and other registers not used
bit 15: during an interrupt is 1 if the dimm board has a command to be executed
bit 14-9: 6 bit command number (naomi bios understands 0 1 3 4 5 6 8 9 a)
bit 7-0: higher 8 bits of 24 bit offset parameter
NAOMI_DIMM_OFFSETL = 5f7040 14000018 (16 bit):
bit 15-0: lower 16 bits of 24 bit offset parameter
NAOMI_DIMM_PARAMETERL = 5f7044 1400001c (16 bit)
NAOMI_DIMM_PARAMETERH = 5f7048 14000020 (16 bit)
NAOMI_DIMM_STATUS = 5f704c 14000024 (16 bit):
bit 0: when 0 signal interrupt from naomi to dimm board
bit 8: when 0 signal interrupt from dimm board to naomi
*/
const device_type NAOMI_GDROM_BOARD = &device_creator<naomi_gdrom_board>;
const UINT32 naomi_gdrom_board::DES_LEFTSWAP[] = {
0x00000000, 0x00000001, 0x00000100, 0x00000101, 0x00010000, 0x00010001, 0x00010100, 0x00010101,
0x01000000, 0x01000001, 0x01000100, 0x01000101, 0x01010000, 0x01010001, 0x01010100, 0x01010101
};
const UINT32 naomi_gdrom_board::DES_RIGHTSWAP[] = {
0x00000000, 0x01000000, 0x00010000, 0x01010000, 0x00000100, 0x01000100, 0x00010100, 0x01010100,
0x00000001, 0x01000001, 0x00010001, 0x01010001, 0x00000101, 0x01000101, 0x00010101, 0x01010101,
};
const UINT32 naomi_gdrom_board::DES_SBOX1[] = {
0x00808200, 0x00000000, 0x00008000, 0x00808202, 0x00808002, 0x00008202, 0x00000002, 0x00008000,
0x00000200, 0x00808200, 0x00808202, 0x00000200, 0x00800202, 0x00808002, 0x00800000, 0x00000002,
0x00000202, 0x00800200, 0x00800200, 0x00008200, 0x00008200, 0x00808000, 0x00808000, 0x00800202,
0x00008002, 0x00800002, 0x00800002, 0x00008002, 0x00000000, 0x00000202, 0x00008202, 0x00800000,
0x00008000, 0x00808202, 0x00000002, 0x00808000, 0x00808200, 0x00800000, 0x00800000, 0x00000200,
0x00808002, 0x00008000, 0x00008200, 0x00800002, 0x00000200, 0x00000002, 0x00800202, 0x00008202,
0x00808202, 0x00008002, 0x00808000, 0x00800202, 0x00800002, 0x00000202, 0x00008202, 0x00808200,
0x00000202, 0x00800200, 0x00800200, 0x00000000, 0x00008002, 0x00008200, 0x00000000, 0x00808002
};
const UINT32 naomi_gdrom_board::DES_SBOX2[] = {
0x40084010, 0x40004000, 0x00004000, 0x00084010, 0x00080000, 0x00000010, 0x40080010, 0x40004010,
0x40000010, 0x40084010, 0x40084000, 0x40000000, 0x40004000, 0x00080000, 0x00000010, 0x40080010,
0x00084000, 0x00080010, 0x40004010, 0x00000000, 0x40000000, 0x00004000, 0x00084010, 0x40080000,
0x00080010, 0x40000010, 0x00000000, 0x00084000, 0x00004010, 0x40084000, 0x40080000, 0x00004010,
0x00000000, 0x00084010, 0x40080010, 0x00080000, 0x40004010, 0x40080000, 0x40084000, 0x00004000,
0x40080000, 0x40004000, 0x00000010, 0x40084010, 0x00084010, 0x00000010, 0x00004000, 0x40000000,
0x00004010, 0x40084000, 0x00080000, 0x40000010, 0x00080010, 0x40004010, 0x40000010, 0x00080010,
0x00084000, 0x00000000, 0x40004000, 0x00004010, 0x40000000, 0x40080010, 0x40084010, 0x00084000
};
const UINT32 naomi_gdrom_board::DES_SBOX3[] = {
0x00000104, 0x04010100, 0x00000000, 0x04010004, 0x04000100, 0x00000000, 0x00010104, 0x04000100,
0x00010004, 0x04000004, 0x04000004, 0x00010000, 0x04010104, 0x00010004, 0x04010000, 0x00000104,
0x04000000, 0x00000004, 0x04010100, 0x00000100, 0x00010100, 0x04010000, 0x04010004, 0x00010104,
0x04000104, 0x00010100, 0x00010000, 0x04000104, 0x00000004, 0x04010104, 0x00000100, 0x04000000,
0x04010100, 0x04000000, 0x00010004, 0x00000104, 0x00010000, 0x04010100, 0x04000100, 0x00000000,
0x00000100, 0x00010004, 0x04010104, 0x04000100, 0x04000004, 0x00000100, 0x00000000, 0x04010004,
0x04000104, 0x00010000, 0x04000000, 0x04010104, 0x00000004, 0x00010104, 0x00010100, 0x04000004,
0x04010000, 0x04000104, 0x00000104, 0x04010000, 0x00010104, 0x00000004, 0x04010004, 0x00010100
};
const UINT32 naomi_gdrom_board::DES_SBOX4[] = {
0x80401000, 0x80001040, 0x80001040, 0x00000040, 0x00401040, 0x80400040, 0x80400000, 0x80001000,
0x00000000, 0x00401000, 0x00401000, 0x80401040, 0x80000040, 0x00000000, 0x00400040, 0x80400000,
0x80000000, 0x00001000, 0x00400000, 0x80401000, 0x00000040, 0x00400000, 0x80001000, 0x00001040,
0x80400040, 0x80000000, 0x00001040, 0x00400040, 0x00001000, 0x00401040, 0x80401040, 0x80000040,
0x00400040, 0x80400000, 0x00401000, 0x80401040, 0x80000040, 0x00000000, 0x00000000, 0x00401000,
0x00001040, 0x00400040, 0x80400040, 0x80000000, 0x80401000, 0x80001040, 0x80001040, 0x00000040,
0x80401040, 0x80000040, 0x80000000, 0x00001000, 0x80400000, 0x80001000, 0x00401040, 0x80400040,
0x80001000, 0x00001040, 0x00400000, 0x80401000, 0x00000040, 0x00400000, 0x00001000, 0x00401040
};
const UINT32 naomi_gdrom_board::DES_SBOX5[] = {
0x00000080, 0x01040080, 0x01040000, 0x21000080, 0x00040000, 0x00000080, 0x20000000, 0x01040000,
0x20040080, 0x00040000, 0x01000080, 0x20040080, 0x21000080, 0x21040000, 0x00040080, 0x20000000,
0x01000000, 0x20040000, 0x20040000, 0x00000000, 0x20000080, 0x21040080, 0x21040080, 0x01000080,
0x21040000, 0x20000080, 0x00000000, 0x21000000, 0x01040080, 0x01000000, 0x21000000, 0x00040080,
0x00040000, 0x21000080, 0x00000080, 0x01000000, 0x20000000, 0x01040000, 0x21000080, 0x20040080,
0x01000080, 0x20000000, 0x21040000, 0x01040080, 0x20040080, 0x00000080, 0x01000000, 0x21040000,
0x21040080, 0x00040080, 0x21000000, 0x21040080, 0x01040000, 0x00000000, 0x20040000, 0x21000000,
0x00040080, 0x01000080, 0x20000080, 0x00040000, 0x00000000, 0x20040000, 0x01040080, 0x20000080
};
const UINT32 naomi_gdrom_board::DES_SBOX6[] = {
0x10000008, 0x10200000, 0x00002000, 0x10202008, 0x10200000, 0x00000008, 0x10202008, 0x00200000,
0x10002000, 0x00202008, 0x00200000, 0x10000008, 0x00200008, 0x10002000, 0x10000000, 0x00002008,
0x00000000, 0x00200008, 0x10002008, 0x00002000, 0x00202000, 0x10002008, 0x00000008, 0x10200008,
0x10200008, 0x00000000, 0x00202008, 0x10202000, 0x00002008, 0x00202000, 0x10202000, 0x10000000,
0x10002000, 0x00000008, 0x10200008, 0x00202000, 0x10202008, 0x00200000, 0x00002008, 0x10000008,
0x00200000, 0x10002000, 0x10000000, 0x00002008, 0x10000008, 0x10202008, 0x00202000, 0x10200000,
0x00202008, 0x10202000, 0x00000000, 0x10200008, 0x00000008, 0x00002000, 0x10200000, 0x00202008,
0x00002000, 0x00200008, 0x10002008, 0x00000000, 0x10202000, 0x10000000, 0x00200008, 0x10002008
};
const UINT32 naomi_gdrom_board::DES_SBOX7[] = {
0x00100000, 0x02100001, 0x02000401, 0x00000000, 0x00000400, 0x02000401, 0x00100401, 0x02100400,
0x02100401, 0x00100000, 0x00000000, 0x02000001, 0x00000001, 0x02000000, 0x02100001, 0x00000401,
0x02000400, 0x00100401, 0x00100001, 0x02000400, 0x02000001, 0x02100000, 0x02100400, 0x00100001,
0x02100000, 0x00000400, 0x00000401, 0x02100401, 0x00100400, 0x00000001, 0x02000000, 0x00100400,
0x02000000, 0x00100400, 0x00100000, 0x02000401, 0x02000401, 0x02100001, 0x02100001, 0x00000001,
0x00100001, 0x02000000, 0x02000400, 0x00100000, 0x02100400, 0x00000401, 0x00100401, 0x02100400,
0x00000401, 0x02000001, 0x02100401, 0x02100000, 0x00100400, 0x00000000, 0x00000001, 0x02100401,
0x00000000, 0x00100401, 0x02100000, 0x00000400, 0x02000001, 0x02000400, 0x00000400, 0x00100001
};
const UINT32 naomi_gdrom_board::DES_SBOX8[] = {
0x08000820, 0x00000800, 0x00020000, 0x08020820, 0x08000000, 0x08000820, 0x00000020, 0x08000000,
0x00020020, 0x08020000, 0x08020820, 0x00020800, 0x08020800, 0x00020820, 0x00000800, 0x00000020,
0x08020000, 0x08000020, 0x08000800, 0x00000820, 0x00020800, 0x00020020, 0x08020020, 0x08020800,
0x00000820, 0x00000000, 0x00000000, 0x08020020, 0x08000020, 0x08000800, 0x00020820, 0x00020000,
0x00020820, 0x00020000, 0x08020800, 0x00000800, 0x00000020, 0x08020020, 0x00000800, 0x00020820,
0x08000800, 0x00000020, 0x08000020, 0x08020000, 0x08020020, 0x08000000, 0x00020000, 0x08000820,
0x00000000, 0x08020820, 0x00020020, 0x08000020, 0x08020000, 0x08000800, 0x08000820, 0x00000000,
0x08020820, 0x00020800, 0x00020800, 0x00000820, 0x00000820, 0x00020020, 0x08000000, 0x08020800
};
const UINT32 naomi_gdrom_board::DES_MASK_TABLE[] = {
0x24000000, 0x10000000, 0x08000000, 0x02080000, 0x01000000,
0x00200000, 0x00100000, 0x00040000, 0x00020000, 0x00010000,
0x00002000, 0x00001000, 0x00000800, 0x00000400, 0x00000200,
0x00000100, 0x00000020, 0x00000010, 0x00000008, 0x00000004,
0x00000002, 0x00000001, 0x20000000, 0x10000000, 0x08000000,
0x04000000, 0x02000000, 0x01000000, 0x00200000, 0x00100000,
0x00080000, 0x00040000, 0x00020000, 0x00010000, 0x00002000,
0x00001000, 0x00000808, 0x00000400, 0x00000200, 0x00000100,
0x00000020, 0x00000011, 0x00000004, 0x00000002
};
const UINT8 naomi_gdrom_board::DES_ROTATE_TABLE[16] = {
1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
};
void naomi_gdrom_board::permutate(UINT32 &a, UINT32 &b, UINT32 m, int shift)
{
UINT32 temp;
temp = ((a>>shift) ^ b) & m;
a ^= temp<<shift;
b ^= temp;
}
void naomi_gdrom_board::des_generate_subkeys(const UINT64 key, UINT32 *subkeys)
{
UINT32 l = key >> 32;
UINT32 r = key;
permutate(r, l, 0x0f0f0f0f, 4);
permutate(r, l, 0x10101010, 0);
l = (DES_LEFTSWAP[(l >> 0) & 0xf] << 3) |
(DES_LEFTSWAP[(l >> 8) & 0xf] << 2) |
(DES_LEFTSWAP[(l >> 16) & 0xf] << 1) |
(DES_LEFTSWAP[(l >> 24) & 0xf] << 0) |
(DES_LEFTSWAP[(l >> 5) & 0xf] << 7) |
(DES_LEFTSWAP[(l >> 13) & 0xf] << 6) |
(DES_LEFTSWAP[(l >> 21) & 0xf] << 5) |
(DES_LEFTSWAP[(l >> 29) & 0xf] << 4);
r = (DES_RIGHTSWAP[(r >> 1) & 0xf] << 3) |
(DES_RIGHTSWAP[(r >> 9) & 0xf] << 2) |
(DES_RIGHTSWAP[(r >> 17) & 0xf] << 1) |
(DES_RIGHTSWAP[(r >> 25) & 0xf] << 0) |
(DES_RIGHTSWAP[(r >> 4) & 0xf] << 7) |
(DES_RIGHTSWAP[(r >> 12) & 0xf] << 6) |
(DES_RIGHTSWAP[(r >> 20) & 0xf] << 5) |
(DES_RIGHTSWAP[(r >> 28) & 0xf] << 4);
l &= 0x0fffffff;
r &= 0x0fffffff;
for(int round = 0; round < 16; round++) {
l = ((l << DES_ROTATE_TABLE[round]) | (l >> (28 - DES_ROTATE_TABLE[round]))) & 0x0fffffff;
r = ((r << DES_ROTATE_TABLE[round]) | (r >> (28 - DES_ROTATE_TABLE[round]))) & 0x0fffffff;
subkeys[round*2] =
((l << 4) & DES_MASK_TABLE[0]) |
((l << 28) & DES_MASK_TABLE[1]) |
((l << 14) & DES_MASK_TABLE[2]) |
((l << 18) & DES_MASK_TABLE[3]) |
((l << 6) & DES_MASK_TABLE[4]) |
((l << 9) & DES_MASK_TABLE[5]) |
((l >> 1) & DES_MASK_TABLE[6]) |
((l << 10) & DES_MASK_TABLE[7]) |
((l << 2) & DES_MASK_TABLE[8]) |
((l >> 10) & DES_MASK_TABLE[9]) |
((r >> 13) & DES_MASK_TABLE[10])|
((r >> 4) & DES_MASK_TABLE[11])|
((r << 6) & DES_MASK_TABLE[12])|
((r >> 1) & DES_MASK_TABLE[13])|
((r >> 14) & DES_MASK_TABLE[14])|
((r >> 0) & DES_MASK_TABLE[15])|
((r >> 5) & DES_MASK_TABLE[16])|
((r >> 10) & DES_MASK_TABLE[17])|
((r >> 3) & DES_MASK_TABLE[18])|
((r >> 18) & DES_MASK_TABLE[19])|
((r >> 26) & DES_MASK_TABLE[20])|
((r >> 24) & DES_MASK_TABLE[21]);
subkeys[round*2+1] =
((l << 15) & DES_MASK_TABLE[22])|
((l << 17) & DES_MASK_TABLE[23])|
((l << 10) & DES_MASK_TABLE[24])|
((l << 22) & DES_MASK_TABLE[25])|
((l >> 2) & DES_MASK_TABLE[26])|
((l << 1) & DES_MASK_TABLE[27])|
((l << 16) & DES_MASK_TABLE[28])|
((l << 11) & DES_MASK_TABLE[29])|
((l << 3) & DES_MASK_TABLE[30])|
((l >> 6) & DES_MASK_TABLE[31])|
((l << 15) & DES_MASK_TABLE[32])|
((l >> 4) & DES_MASK_TABLE[33])|
((r >> 2) & DES_MASK_TABLE[34])|
((r << 8) & DES_MASK_TABLE[35])|
((r >> 14) & DES_MASK_TABLE[36])|
((r >> 9) & DES_MASK_TABLE[37])|
((r >> 0) & DES_MASK_TABLE[38])|
((r << 7) & DES_MASK_TABLE[39])|
((r >> 7) & DES_MASK_TABLE[40])|
((r >> 3) & DES_MASK_TABLE[41])|
((r << 2) & DES_MASK_TABLE[42])|
((r >> 21) & DES_MASK_TABLE[43]);
}
}
UINT64 naomi_gdrom_board::des_encrypt_decrypt(bool decrypt, UINT64 src, const UINT32 *des_subkeys)
{
UINT32 r = (src & 0x00000000ffffffffULL) >> 0;
UINT32 l = (src & 0xffffffff00000000ULL) >> 32;
permutate(l, r, 0x0f0f0f0f, 4);
permutate(l, r, 0x0000ffff, 16);
permutate(r, l, 0x33333333, 2);
permutate(r, l, 0x00ff00ff, 8);
permutate(l, r, 0x55555555, 1);
int subkey;
if(decrypt)
subkey = 30;
else
subkey = 0;
for(int i = 0; i < 32 ; i+=4) {
UINT32 temp;
temp = ((r<<1) | (r>>31)) ^ des_subkeys[subkey];
l ^= DES_SBOX8[ (temp>>0) & 0x3f ];
l ^= DES_SBOX6[ (temp>>8) & 0x3f ];
l ^= DES_SBOX4[ (temp>>16) & 0x3f ];
l ^= DES_SBOX2[ (temp>>24) & 0x3f ];
subkey++;
temp = ((r>>3) | (r<<29)) ^ des_subkeys[subkey];
l ^= DES_SBOX7[ (temp>>0) & 0x3f ];
l ^= DES_SBOX5[ (temp>>8) & 0x3f ];
l ^= DES_SBOX3[ (temp>>16) & 0x3f ];
l ^= DES_SBOX1[ (temp>>24) & 0x3f ];
subkey++;
if(decrypt)
subkey -= 4;
temp = ((l<<1) | (l>>31)) ^ des_subkeys[subkey];
r ^= DES_SBOX8[ (temp>>0) & 0x3f ];
r ^= DES_SBOX6[ (temp>>8) & 0x3f ];
r ^= DES_SBOX4[ (temp>>16) & 0x3f ];
r ^= DES_SBOX2[ (temp>>24) & 0x3f ];
subkey++;
temp = ((l>>3) | (l<<29)) ^ des_subkeys[subkey];
r ^= DES_SBOX7[ (temp>>0) & 0x3f ];
r ^= DES_SBOX5[ (temp>>8) & 0x3f ];
r ^= DES_SBOX3[ (temp>>16) & 0x3f ];
r ^= DES_SBOX1[ (temp>>24) & 0x3f ];
subkey++;
if(decrypt)
subkey -= 4;
}
permutate(r, l, 0x55555555, 1);
permutate(l, r, 0x00ff00ff, 8);
permutate(l, r, 0x33333333, 2);
permutate(r, l, 0x0000ffff, 16);
permutate(r, l, 0x0f0f0f0f, 4);
return (UINT64(r) << 32) | UINT64(l);
}
UINT64 naomi_gdrom_board::rev64(UINT64 src)
{
UINT64 ret;
ret = ((src & 0x00000000000000ffULL) << 56)
| ((src & 0x000000000000ff00ULL) << 40)
| ((src & 0x0000000000ff0000ULL) << 24)
| ((src & 0x00000000ff000000ULL) << 8 )
| ((src & 0x000000ff00000000ULL) >> 8 )
| ((src & 0x0000ff0000000000ULL) >> 24)
| ((src & 0x00ff000000000000ULL) >> 40)
| ((src & 0xff00000000000000ULL) >> 56);
return ret;
}
UINT64 naomi_gdrom_board::read_to_qword(const UINT8 *region)
{
UINT64 ret = 0;
for(int i=0;i<8;i++)
ret |= UINT64(region[i]) << (56-(8*i));
return ret;
}
void naomi_gdrom_board::write_from_qword(UINT8 *region, UINT64 qword)
{
for(int i=0;i<8;i++)
region[i] = qword >> (56-(i*8));
}
naomi_gdrom_board::naomi_gdrom_board(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: naomi_board(mconfig, NAOMI_GDROM_BOARD, "NAOMI-GDROM-BOARD", tag, owner, clock)
{
image_tag = 0;
pic_tag = 0;
}
void naomi_gdrom_board::static_set_tags(device_t &device, const char *_image_tag, const char *_pic_tag)
{
naomi_gdrom_board &dev = downcast<naomi_gdrom_board &>(device);
dev.image_tag = _image_tag;
dev.pic_tag = _pic_tag;
}
void naomi_gdrom_board::find_file(const char *name, const UINT8 *dir_sector, UINT32 &file_start, UINT32 &file_size)
{
file_start = 0;
file_size = 0;
logerror("Looking for file %s\n", name);
for(UINT32 pos = 0; pos < 2048; pos += dir_sector[pos]) {
int fnlen = 0;
if(!(dir_sector[pos+25] & 2)) {
int len = dir_sector[pos+32];
for(fnlen=0; fnlen < FILENAME_LENGTH; fnlen++) {
if((dir_sector[pos+33+fnlen] == ';') && (name[fnlen] == 0)) {
fnlen = FILENAME_LENGTH+1;
break;
}
if(dir_sector[pos+33+fnlen] != name[fnlen])
break;
if(fnlen == len) {
if(name[fnlen] == 0)
fnlen = FILENAME_LENGTH+1;
else
fnlen = FILENAME_LENGTH;
}
}
}
if(fnlen == FILENAME_LENGTH+1) {
// start sector and size of file
file_start = ((dir_sector[pos+2] << 0) |
(dir_sector[pos+3] << 8) |
(dir_sector[pos+4] << 16) |
(dir_sector[pos+5] << 24));
file_size = ((dir_sector[pos+10] << 0) |
(dir_sector[pos+11] << 8) |
(dir_sector[pos+12] << 16) |
(dir_sector[pos+13] << 24));
logerror("start %08x size %08x\n", file_start, file_size);
break;
}
if (dir_sector[pos] == 0)
break;
}
}
void naomi_gdrom_board::device_start()
{
naomi_board::device_start();
dimm_data = 0;
dimm_data_size = 0;
char name[128];
memset(name,'\0',128);
UINT64 key;
const UINT8 *picdata = machine().region(pic_tag)->base();
if(machine().region(pic_tag)->bytes() == 0x4000) {
//printf("Real PIC binary found\n");
for(int i=0;i<7;i++)
name[i] = picdata[0x7c0+i*2];
for(int i=0;i<7;i++)
name[i+7] = picdata[0x7e0+i*2];
key = 0;
for(int i=0;i<7;i++)
key |= UINT64(picdata[0x780+i*2]) << (56 - i*8);
key |= picdata[0x7a0];
} else {
// use extracted pic data
logerror("This PIC key hasn't been converted to a proper PIC binary yet!\n");
memcpy(name, picdata+33, 7);
memcpy(name+7, picdata+25, 7);
key =((UINT64(picdata[0x31]) << 56) |
(UINT64(picdata[0x32]) << 48) |
(UINT64(picdata[0x33]) << 40) |
(UINT64(picdata[0x34]) << 32) |
(UINT64(picdata[0x35]) << 24) |
(UINT64(picdata[0x36]) << 16) |
(UINT64(picdata[0x37]) << 8) |
(UINT64(picdata[0x29]) << 0));
}
logerror("key is %08x%08x\n", (UINT32)((key & 0xffffffff00000000ULL)>>32), (UINT32)(key & 0x00000000ffffffffULL));
UINT8 buffer[2048];
cdrom_file *gdromfile = cdrom_open(get_disk_handle(machine(), image_tag));
// primary volume descriptor
// read frame 0xb06e (frame=sector+150)
// dimm board firmware starts straight from this frame
cdrom_read_data(gdromfile, 0xb06e - 150, buffer, CD_TRACK_MODE1);
UINT32 path_table = ((buffer[0x8c+0] << 0) |
(buffer[0x8c+1] << 8) |
(buffer[0x8c+2] << 16) |
(buffer[0x8c+3] << 24));
// path table
cdrom_read_data(gdromfile, path_table, buffer, CD_TRACK_MODE1);
UINT32 dir = ((buffer[0x2+0] << 0) |
(buffer[0x2+1] << 8) |
(buffer[0x2+2] << 16) |
(buffer[0x2+3] << 24));
// directory
UINT8 dir_sector[2048];
cdrom_read_data(gdromfile, dir, dir_sector, CD_TRACK_MODE1);
// find data of file
UINT32 file_start, file_size;
find_file(name, dir_sector, file_start, file_size);
if(file_start && (file_size == 0x100)) {
// read file
cdrom_read_data(gdromfile, file_start, buffer, CD_TRACK_MODE1);
// get "rom" file name
memset(name,'\0', 128);
memcpy(name, buffer+0xc0, FILENAME_LENGTH-1);
find_file(name, dir_sector, file_start, file_size);
if(file_start) {
UINT32 file_rounded_size = (file_size+2047) & -2048;
for(dimm_data_size = 4096; dimm_data_size < file_rounded_size; dimm_data_size <<= 1);
dimm_data = auto_alloc_array(machine(), UINT8, dimm_data_size);
if(dimm_data_size != file_rounded_size)
memset(dimm_data + file_rounded_size, 0, dimm_data_size - file_rounded_size);
// read encrypted data into dimm_data
UINT32 sectors = file_rounded_size / 2048;
for(UINT32 sec = 0; sec != sectors; sec++)
cdrom_read_data(gdromfile, file_start+sec, dimm_data + 2048*sec, CD_TRACK_MODE1);
UINT32 des_subkeys[32];
des_generate_subkeys(rev64(key), des_subkeys);
for(int i=0; i<file_rounded_size;i+=8)
write_from_qword(dimm_data+i, rev64(des_encrypt_decrypt(true, rev64(read_to_qword(dimm_data+i)), des_subkeys)));
}
}
// decrypt loaded data
cdrom_close(gdromfile);
if(!dimm_data)
throw emu_fatalerror("GDROM: Could not find the file to decrypt.");
save_item(NAME(dimm_cur_address));
}
void naomi_gdrom_board::device_reset()
{
naomi_board::device_reset();
dimm_cur_address = 0;
}
void naomi_gdrom_board::board_setup_address(UINT32 address, bool is_dma)
{
dimm_cur_address = address & (dimm_data_size-1);
}
void naomi_gdrom_board::board_get_buffer(UINT8 *&base, UINT32 &limit)
{
base = dimm_data + dimm_cur_address;
limit = dimm_data_size - dimm_cur_address;
}
void naomi_gdrom_board::board_advance(UINT32 size)
{
dimm_cur_address += size;
if(dimm_cur_address >= dimm_data_size)
dimm_cur_address %= dimm_data_size;
}

View File

@ -0,0 +1,61 @@
#ifndef _NAOMIGD_H_
#define _NAOMIGD_H_
#include "naomibd.h"
#define MCFG_NAOMI_GDROM_BOARD_ADD(_tag, _image_tag, _pic_tag, _eeprom_tag, _maincpu_tag, _irq_cb) \
MCFG_NAOMI_BOARD_ADD(_tag, NAOMI_GDROM_BOARD, _eeprom_tag, _maincpu_tag, _irq_cb) \
naomi_gdrom_board::static_set_tags(*device, _image_tag, _pic_tag);
class naomi_gdrom_board : public naomi_board
{
public:
naomi_gdrom_board(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
static void static_set_tags(device_t &device, const char *_image_tag, const char *_pic_tag);
protected:
virtual void device_start();
virtual void device_reset();
virtual void board_setup_address(UINT32 address, bool is_dma);
virtual void board_get_buffer(UINT8 *&base, UINT32 &limit);
virtual void board_advance(UINT32 size);
private:
enum { FILENAME_LENGTH=24 };
const char *image_tag, *pic_tag;
UINT32 dimm_cur_address;
// Note: voluntarily not saved into the state
UINT8 *dimm_data;
UINT32 dimm_data_size;
static const UINT32 DES_LEFTSWAP[];
static const UINT32 DES_RIGHTSWAP[];
static const UINT32 DES_SBOX1[];
static const UINT32 DES_SBOX2[];
static const UINT32 DES_SBOX3[];
static const UINT32 DES_SBOX4[];
static const UINT32 DES_SBOX5[];
static const UINT32 DES_SBOX6[];
static const UINT32 DES_SBOX7[];
static const UINT32 DES_SBOX8[];
static const UINT32 DES_MASK_TABLE[];
static const UINT8 DES_ROTATE_TABLE[16];
void find_file(const char *name, const UINT8 *dir_sector, UINT32 &file_start, UINT32 &file_size);
inline void permutate(UINT32 &a, UINT32 &b, UINT32 m, int shift);
void des_generate_subkeys(const UINT64 key, UINT32 *subkeys);
UINT64 des_encrypt_decrypt(bool decrypt, UINT64 src, const UINT32 *des_subkeys);
UINT64 rev64(UINT64 src);
UINT64 read_to_qword(const UINT8 *region);
void write_from_qword(UINT8 *region, UINT64 qword);
};
extern const device_type NAOMI_GDROM_BOARD;
#endif

View File

@ -0,0 +1,223 @@
#define ADDRESS_MAP_MODERN
#include "emu.h"
#include "naomim1.h"
const device_type NAOMI_M1_BOARD = &device_creator<naomi_m1_board>;
DEVICE_ADDRESS_MAP_START(submap, 16, naomi_m1_board)
AM_RANGE(0x0a, 0x0b) AM_READ(actel_id_r)
AM_INHERIT_FROM(naomi_board::submap)
ADDRESS_MAP_END
naomi_m1_board::naomi_m1_board(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: naomi_board(mconfig, NAOMI_M1_BOARD, "NAOMI-M1-BOARD", tag, owner, clock)
{
key_tag = 0;
}
void naomi_m1_board::static_set_tags(device_t &device, const char *_key_tag)
{
naomi_m1_board &dev = downcast<naomi_m1_board &>(device);
dev.key_tag = _key_tag;
}
READ16_MEMBER(naomi_m1_board::actel_id_r)
{
return 0x0000;
}
void naomi_m1_board::device_start()
{
naomi_board::device_start();
const UINT8 *key_data = machine().region(key_tag)->base();
key = (key_data[0] << 24) | (key_data[1] << 16) | (key_data[2] << 8) | key_data[3];
buffer = auto_alloc_array(machine(), UINT8, BUFFER_SIZE);
save_pointer(NAME(buffer), BUFFER_SIZE);
save_item(NAME(dict));
save_item(NAME(hist));
save_item(NAME(rom_cur_address));
save_item(NAME(buffer_actual_size));
save_item(NAME(avail_bits));
save_item(NAME(encryption));
save_item(NAME(stream_ended));
save_item(NAME(has_history));
}
void naomi_m1_board::device_reset()
{
naomi_board::device_reset();
encryption = false;
rom_cur_address = 0;
buffer_actual_size = 0;
has_history = false;
stream_ended = false;
memset(dict, 0, sizeof(dict));
memset(hist, 0, sizeof(hist));
avail_val = 0;
avail_bits = 0;
}
void naomi_m1_board::board_setup_address(UINT32 address, bool is_dma)
{
rom_cur_address = address & 0x1fffffff;
encryption = (!(address & 0x20000000)) && is_dma;
if(encryption) {
enc_reset();
enc_fill();
}
}
void naomi_m1_board::board_get_buffer(UINT8 *&base, UINT32 &limit)
{
if(encryption) {
base = buffer;
limit = BUFFER_SIZE;
} else {
base = m_region->base() + rom_cur_address;
limit = m_region->bytes() - rom_cur_address;
}
}
void naomi_m1_board::board_advance(UINT32 size)
{
if(encryption) {
if(size < buffer_actual_size) {
memmove(buffer, buffer + size, buffer_actual_size - size);
buffer_actual_size -= size;
} else {
hist[0] = buffer[buffer_actual_size-2];
hist[1] = buffer[buffer_actual_size-1];
has_history = true;
buffer_actual_size = 0;
}
enc_fill();
} else
rom_cur_address += size;
}
UINT32 naomi_m1_board::get_decrypted_32b()
{
UINT8 *base = m_region->base() + rom_cur_address;
UINT8 a = base[0];
UINT8 b = base[1];
UINT8 c = base[2];
UINT8 d = base[3];
rom_cur_address += 4;
UINT32 res = key ^ (((b^d) << 24) | ((a^c) << 16) | (b << 8) | a);
return res;
}
void naomi_m1_board::gb_reset()
{
avail_val = 0;
avail_bits = 0;
}
inline UINT32 naomi_m1_board::lookb(int bits)
{
if(bits > avail_bits) {
avail_val = (avail_val << 32) | get_decrypted_32b();
avail_bits += 32;
}
return (avail_val >> (avail_bits - bits)) & ((1 << bits)-1);
}
inline void naomi_m1_board::skipb(int bits)
{
avail_bits -= bits;
}
inline UINT32 naomi_m1_board::getb(int bits)
{
UINT32 res = lookb(bits);
skipb(bits);
return res;
}
void naomi_m1_board::enc_reset()
{
gb_reset();
stream_ended = false;
has_history = false;
buffer_actual_size = 0;
for(int i=0; i<111; i++)
dict[i] = getb(8);
}
void naomi_m1_board::wb(UINT8 byte)
{
if(dict[0] & 64)
if(buffer_actual_size < 2)
if(has_history)
buffer[buffer_actual_size] = hist[buffer_actual_size] - byte;
else
buffer[buffer_actual_size] = byte;
else
buffer[buffer_actual_size] = buffer[buffer_actual_size-2] - byte;
else
buffer[buffer_actual_size] = byte;
buffer_actual_size++;
}
void naomi_m1_board::enc_fill()
{
while(buffer_actual_size < BUFFER_SIZE && !stream_ended) {
switch(lookb(3)) {
// 00+2 - 0000+esc
case 0: case 1: {
skipb(2);
int addr = getb(2);
if(addr)
wb(dict[addr]);
else
wb(getb(8));
break;
}
// 010+2
case 2:
skipb(3);
wb(dict[getb(2)+4]);
break;
// 011+3
case 3:
skipb(3);
wb(dict[getb(3)+8]);
break;
// 10+5
case 4: case 5:
skipb(2);
wb(dict[getb(5)+16]);
break;
// 11+6
case 6: case 7: {
skipb(2);
int addr = getb(6)+48;
if(addr == 111)
stream_ended = true;
else
wb(dict[addr]);
break;
}
}
}
while(buffer_actual_size < BUFFER_SIZE)
buffer[buffer_actual_size++] = 0;
}

View File

@ -0,0 +1,56 @@
#ifndef _NAOMIM1_H_
#define _NAOMIM1_H_
#include "naomibd.h"
#define MCFG_NAOMI_M1_BOARD_ADD(_tag, _key_tag, _eeprom_tag, _maincpu_tag, _irq_cb) \
MCFG_NAOMI_BOARD_ADD(_tag, NAOMI_M1_BOARD, _eeprom_tag, _maincpu_tag, _irq_cb) \
naomi_m1_board::static_set_tags(*device, _key_tag);
class naomi_m1_board : public naomi_board
{
public:
naomi_m1_board(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
static void static_set_tags(device_t &device, const char *_key_tag);
virtual DECLARE_ADDRESS_MAP(submap, 16);
DECLARE_READ16_MEMBER(actel_id_r);
protected:
virtual void device_start();
virtual void device_reset();
virtual void board_setup_address(UINT32 address, bool is_dma);
virtual void board_get_buffer(UINT8 *&base, UINT32 &limit);
virtual void board_advance(UINT32 size);
private:
enum { BUFFER_SIZE = 32768 };
const char *key_tag;
UINT32 key;
UINT8 *buffer;
UINT8 dict[111], hist[2];
UINT64 avail_val;
UINT32 rom_cur_address, buffer_actual_size, avail_bits;
bool encryption, stream_ended, has_history;
void gb_reset();
UINT32 lookb(int bits);
void skipb(int bits);
UINT32 getb(int bits);
void enc_reset();
void enc_fill();
UINT32 get_decrypted_32b();
void wb(UINT8 byte);
};
extern const device_type NAOMI_M1_BOARD;
#endif

View File

@ -0,0 +1,839 @@
#define ADDRESS_MAP_MODERN
#include "emu.h"
#include "naomim2.h"
const device_type NAOMI_M2_BOARD = &device_creator<naomi_m2_board>;
naomi_m2_board::naomi_m2_board(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: naomi_board(mconfig, NAOMI_M2_BOARD, "NAOMI-M2-BOARD", tag, owner, clock)
{
key_tag = 0;
}
void naomi_m2_board::static_set_tags(device_t &device, const char *_key_tag)
{
naomi_m2_board &dev = downcast<naomi_m2_board &>(device);
dev.key_tag = _key_tag;
}
void naomi_m2_board::device_start()
{
naomi_board::device_start();
const UINT8 *key_data = machine().region(key_tag)->base();
key = (key_data[0] << 24) | (key_data[1] << 16) | (key_data[2] << 8) | key_data[3];
ram = auto_alloc_array(machine(), UINT8, RAM_SIZE);
buffer = auto_alloc_array(machine(), UINT8, BUFFER_SIZE);
line_buffer = auto_alloc_array(machine(), UINT8, LINE_SIZE);
line_buffer_prev = auto_alloc_array(machine(), UINT8, LINE_SIZE);
save_pointer(NAME(ram), RAM_SIZE);
save_pointer(NAME(buffer), BUFFER_SIZE);
save_pointer(NAME(line_buffer), LINE_SIZE);
save_pointer(NAME(line_buffer_prev), LINE_SIZE);
save_item(NAME(rom_cur_address));
save_item(NAME(prot_cur_address));
save_item(NAME(subkey));
save_item(NAME(enc_ready));
save_item(NAME(dec_hist));
save_item(NAME(dec_header));
save_item(NAME(buffer_pos));
save_item(NAME(line_buffer_pos));
save_item(NAME(line_buffer_size));
}
void naomi_m2_board::device_reset()
{
naomi_board::device_reset();
memset(ram, 0, RAM_SIZE);
memset(buffer, 0, BUFFER_SIZE);
memset(line_buffer, 0, LINE_SIZE);
memset(line_buffer_prev, 0, LINE_SIZE);
rom_cur_address = 0;
prot_cur_address = 0;
subkey = 0;
dec_hist = 0;
dec_header = 0;
enc_ready = false;
buffer_pos = 0;
line_buffer_pos = 0;
line_buffer_size = 0;
buffer_bit = 0;
}
void naomi_m2_board::board_setup_address(UINT32 address, bool is_dma)
{
rom_cur_address = address;
}
void naomi_m2_board::board_get_buffer(UINT8 *&base, UINT32 &limit)
{
if(rom_cur_address & 0x40000000) {
if(rom_cur_address == 0x4001fffe) {
if(!enc_ready)
enc_start();
if(dec_header & FLAG_COMPRESSED) {
if(line_buffer_pos == line_buffer_size)
line_fill();
base = line_buffer + line_buffer_pos;
line_buffer_pos += 2;
} else {
if(buffer_pos == BUFFER_SIZE)
enc_fill();
base = buffer + buffer_pos;
buffer_pos += 2;
}
limit = 2;
} else
throw emu_fatalerror("NAOMIM2: Unsupported, read from %08x", rom_cur_address);
} else {
base = m_region->base() + (rom_cur_address & 0x1fffffff);
limit = m_region->bytes() - (rom_cur_address & 0x1fffffff);
}
}
void naomi_m2_board::board_advance(UINT32 size)
{
rom_cur_address += size;
}
void naomi_m2_board::board_write(offs_t offset, UINT16 data)
{
if(offset & 0x40000000) {
if((offset & 0x0f000000) == 0x02000000) {
offset &= RAM_SIZE-1;
ram[offset] = data;
ram[offset+1] = data >> 8;
return;
}
switch(offset & 0x1fffffff) {
case 0x1fff8: prot_cur_address = (prot_cur_address & 0xffff0000) | data; enc_ready = false; return;
case 0x1fffa: prot_cur_address = (prot_cur_address & 0x0000ffff) | (data << 16); enc_ready = false; return;
case 0x1fffc: subkey = data; enc_ready = false; return;
}
}
throw emu_fatalerror("NAOMIM2: unhandled board write %08x, %04x\n", offset, data);
}
/***************************************************************************
DECRYPTION EMULATION
By convention, we label the three known cart protection methods this way (using Deunan Knute's wording):
M1: DMA read of protected ROM area
M2: special read of ROM area which supplies decryption key first
M3: normal read followed by write to cart's decryption buffer (up to 64kB), followed by M2 but from buffer area
Notes below refer to M2 & M3.
The encryption is done by a stream cipher operating in counter mode, which use a 16-bits internal block cipher.
There are 2 "control bits" at the start of the decrypted stream which control the mode of operation: bit #1 set to 1 means
that the decrypted stream needs to be decompressed after being decrypted. More on this later.
The next 16-bits are part of the header (they don't belong to the plaintext), but his meaning is unclear. It has been
conjectured that it could stablish when to "reset" the process and start processing a new stream (based on some tests
on WWFROYAL, in which the decryption's output doesn't seem to be valid for more than some dozens of words), but some
more testing would be needed for clarifying that.
After those 18 heading bits, we find the proper plaintext. It must be noted that, due to the initial 2 special bits,
the 16-bits words of the plaintext are shifted 2 bits respect to the word-boundaries of the output stream of the
internal block-cipher. So, at a given step, the internal block cipher will output 16-bits, 14 of which will go to a
given plaintext word, and the remaining 2 to the next plaintext word.
The underlying block cipher consists of two 4-round Feistel Networks (FN): the first one takes the counter (16 bits),
the game-key (>=26 bits) and the sequence-key (16 bits) and output a middle result (16 bits) which will act as another key
for the second one. The second FN will take the encrypted word (16 bits), the game-key, the sequence-key and the result
from the first FN and will output the decrypted word (16 bits).
Each round of the Feistel Networks use four substitution sboxes, each having 6 inputs and 2 outputs. The input can be the
XOR of at most two "sources bits", being source bits the bits from the previous round and the bits from the different keys.
The underlying block cipher has the same structure than the one used by the CPS-2 (Capcom Play System 2) and,
indeed, some of the used sboxes are exactly the same and appear in the same FN/round in both systems (this is not evident,
as you need to apply a bitswapping and some XORs to the input & output of the sboxes to get the same values due). However,
the key scheduling used by this implementation is much weaker than the CPS-2's one. Many s-boxes inputs are XORed with any
key bit.
Due to the small key-length, no sophisticated attacks are needed to recover the keys; a brute-force attack knowing just
some (encrypted word-decrypted word) pairs suffice. However, due to the weak key scheduling, it should be noted that some
related keys can produce the same output bytes for some (short) input sequences.
The only difference in the decryption process between M2 and M3 is the initialization of the counter. In M3, the counter is
always set to 0 at the beginning of the decryption while, in M2, the bits #1-#16 of the ciphertext's address are used
to initialize the counter.
Note that this implementation considers that the counter initialization for ram decryption is 0 simply because the ram is
mapped to multiples of 128K.
Due to the nature of the cipher, there are some degrees of freedom when choosing the s-boxes and keys values; by example,
you could apply a fixed bitswapping and XOR to the keys and the decryption would remain the same as long as you change
accordingly the s-boxes' definitions. So the order of the bits in the keys is arbitrary, and the s-boxes values have been
chosen so as to make the key for CAPSNK equal to 0.
It can be observed that a couple of sboxes have incomplete tables (a 255 value indicate an unknown value). The recovered keys
as of december/2010 show small randomness and big correlations, making possible that some unseen bits could make the
decryption need those incomplete parts.
****************************************************************************************/
const naomi_m2_board::sbox naomi_m2_board::fn1_sboxes[4][4] = {
{ // 1st round
{
{
0,3,2,2,1,3,1,2,3,2,1,2,1,2,3,1,3,2,2,0,2,1,3,0,0,3,2,3,2,1,2,0,
2,3,1,1,2,2,1,1,1,0,2,3,3,0,2,1,1,1,1,1,3,0,3,2,1,0,1,2,0,3,1,3,
},
{3,4,5,7,-1,-1},
{0,4}
},
{
{
2,2,2,0,3,3,0,1,2,2,3,2,3,0,2,2,1,1,0,3,3,2,0,2,0,1,0,1,2,3,1,1,
0,1,3,3,1,3,3,1,2,3,2,0,0,0,2,2,0,3,1,3,0,3,2,2,0,3,0,3,1,1,0,2,
},
{0,1,2,5,6,7},
{1,6}
},
{
{
0,1,3,0,3,1,1,1,1,2,3,1,3,0,2,3,3,2,0,2,1,1,2,1,1,3,1,0,0,2,0,1,
1,3,1,0,0,3,2,3,2,0,3,3,0,0,0,0,1,2,3,3,2,0,3,2,1,0,0,0,2,2,3,3,
},
{0,2,5,6,7,-1},
{2,3}
},
{
{
3,2,1,2,1,2,3,2,0,3,2,2,3,1,3,3,0,2,3,0,3,3,2,1,1,1,2,0,2,2,0,1,
1,3,3,0,0,3,0,3,0,2,1,3,2,1,0,0,0,1,1,2,0,1,0,0,0,1,3,3,2,0,3,3,
},
{1,2,3,4,6,7},
{5,7}
},
},
{ // 2nd round
{
{
3,3,1,2,0,0,2,2,2,1,2,1,3,1,1,3,3,0,0,3,0,3,3,2,1,1,3,2,3,2,1,3,
2,3,0,1,3,2,0,1,2,1,3,1,2,2,3,3,3,1,2,2,0,3,1,2,2,1,3,0,3,0,1,3,
},
{0,1,3,4,5,7},
{0,4}
},
{
{
2,0,1,0,0,3,2,0,3,3,1,2,1,3,0,2,0,2,0,0,0,2,3,1,3,1,1,2,3,0,3,0,
3,0,2,0,0,2,2,1,0,2,3,3,1,3,1,0,1,3,3,0,0,1,3,1,0,2,0,3,2,1,0,1,
},
{0,1,3,4,6,-1},
{1,5}
},
{
{
2,2,2,3,1,1,0,1,0,1,2,2,3,3,0,2,0,3,2,3,3,0,2,1,0,3,1,0,0,2,3,2,
3,2,0,3,2,0,1,0,3,3,1,1,2,2,2,0,2,1,3,1,1,1,1,2,2,2,3,0,1,3,0,0,
},
{1,2,5,6,7,-1},
{2,7}
},
{
{
0,1,3,3,3,1,3,3,1,0,2,0,2,0,0,3,1,2,1,3,1,2,3,2,2,0,1,3,0,3,3,3,
0,0,0,2,1,1,2,3,2,2,3,1,1,2,0,2,0,2,1,3,1,1,3,3,1,1,3,0,2,3,0,0,
},
{2,3,4,5,6,7},
{3,6}
},
},
{ // 3rd round
{
{
0,0,1,0,1,0,0,3,2,0,0,3,0,1,0,2,0,3,0,0,2,0,3,2,2,1,3,2,2,1,1,2,
0,0,0,3,0,1,1,0,0,2,1,0,3,1,2,2,2,0,3,1,3,0,1,2,2,1,1,1,0,2,3,1,
},
{1,2,3,4,5,7},
{0,5}
},
{
{
1,2,1,0,3,1,1,2,0,0,2,3,2,3,1,3,2,0,3,2,2,3,1,1,1,1,0,3,2,0,0,1,
1,0,0,1,3,1,2,3,0,0,2,3,3,0,1,0,0,2,3,0,1,2,0,1,3,3,3,1,2,0,2,1,
},
{0,2,4,5,6,7},
{1,6}
},
{
{
0,3,0,2,1,2,0,0,1,1,0,0,3,1,1,0,0,3,0,0,2,3,3,2,3,1,2,0,0,2,3,0,
// unused?
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
},
{0,2,4,6,7,-1},
{2,3}
},
{
{
0,0,1,0,0,1,0,2,3,3,0,3,3,2,3,0,2,2,2,0,3,2,0,3,1,0,0,3,3,0,0,0,
2,2,1,0,2,0,3,2,0,0,3,1,3,3,0,0,2,1,1,2,1,0,1,1,0,3,1,2,0,2,0,3,
},
{0,1,2,3,6,-1},
{4,7}
},
},
{ // 4th round
{
{
0,3,3,3,3,3,2,0,0,1,2,0,2,2,2,2,1,1,0,2,2,1,3,2,3,2,0,1,2,3,2,1,
3,2,2,3,1,0,1,0,0,2,0,1,2,1,2,3,1,2,1,1,2,2,1,0,1,3,2,3,2,0,3,1,
},
{0,1,3,4,5,6},
{0,5}
},
{
{
0,3,0,0,2,0,3,1,1,1,2,2,2,1,3,1,2,2,1,3,2,2,3,3,0,3,1,0,3,2,0,1,
3,0,2,0,1,0,2,1,3,3,1,2,2,0,2,3,3,2,3,0,1,1,3,3,0,2,1,3,0,2,2,3,
},
{0,1,2,3,5,7},
{1,7}
},
{
{
0,1,2,3,3,3,3,1,2,0,2,3,2,1,0,1,2,2,1,2,0,3,2,0,1,1,0,1,3,1,3,1,
3,1,0,0,1,0,0,0,0,1,2,2,1,1,3,3,1,2,3,3,3,2,3,0,2,2,1,3,3,0,2,0,
},
{2,3,4,5,6,7},
{2,3}
},
{
{
0,2,1,1,3,2,0,3,1,0,1,0,3,2,1,1,2,2,0,3,1,0,1,2,2,2,3,3,0,0,0,0,
1,2,1,0,2,1,2,2,2,3,2,3,0,1,3,0,0,1,3,0,0,1,1,0,1,0,0,0,0,2,0,1,
},
{0,1,2,4,6,7},
{4,6}
},
},
};
const naomi_m2_board::sbox naomi_m2_board::fn2_sboxes[4][4] = {
{ // 1st round
{
{
3,3,0,1,0,1,0,0,0,3,0,0,1,3,1,2,0,3,3,3,2,1,0,1,1,1,2,2,2,3,2,2,
2,1,3,3,1,3,1,1,0,0,1,2,0,2,2,1,1,2,3,1,2,1,3,1,2,2,0,1,3,0,2,2,
},
{1,3,4,5,6,7},
{0,7}
},
{
{
0,2,3,2,1,1,0,0,2,1,0,3,3,0,0,0,3,2,0,2,1,1,2,1,0,0,3,1,2,2,3,1,
3,1,3,0,0,0,1,3,1,0,0,3,2,2,3,1,1,3,0,0,2,1,3,3,1,3,1,2,3,1,2,1,
},
{0,3,5,6,-1,-1},
{1,2}
},
{
{
0,2,2,1,0,1,2,1,2,0,1,2,3,3,0,1,3,1,1,2,1,2,1,3,3,2,3,3,2,1,0,1,
0,1,0,2,0,1,1,3,2,0,3,2,1,1,1,3,2,3,0,2,3,0,2,2,1,3,0,1,1,2,2,2,
},
{0,2,3,4,7,-1},
{3,4}
},
{
{
2,3,1,3,2,0,1,2,0,0,3,3,3,3,3,1,2,0,2,1,2,3,0,2,0,1,0,3,0,2,1,0,
2,3,0,1,3,0,3,2,3,1,2,0,3,1,1,2,0,3,0,0,2,0,2,1,2,2,3,2,1,2,3,1,
},
{1,2,5,6,-1,-1},
{5,6}
},
},
{ // 2nd round
{
{
2,3,1,3,1,0,3,3,3,2,3,3,2,0,0,3,2,3,0,3,1,1,2,3,1,1,2,2,0,1,0,0,
2,1,0,1,2,0,1,2,0,3,1,1,2,3,1,2,0,2,0,1,3,0,1,0,2,2,3,0,3,2,3,0,
},
{0,1,4,5,6,7},
{0,7}
},
{
{
0,2,2,0,2,2,0,3,2,3,2,1,3,2,3,3,1,1,0,0,3,0,2,1,1,3,3,2,3,2,0,1,
1,2,3,0,1,0,3,0,3,1,0,2,1,2,0,3,2,3,1,2,2,0,3,2,3,0,0,1,2,3,3,3,
},
{0,2,3,6,7,-1},
{1,5}
},
{
{
1,2,3,2,0,3,2,3,0,1,1,0,0,2,2,3,2,0,0,3,0,2,3,3,2,2,1,0,2,1,0,3,
1,0,2,0,1,1,0,1,0,0,1,0,3,0,3,3,2,2,0,2,1,1,1,0,3,0,1,3,2,3,2,1,
},
{2,3,4,6,7,-1},
{2,3}
},
{
{
2,3,1,3,1,1,2,3,3,1,1,0,1,0,2,3,2,1,0,0,2,2,0,1,0,2,2,2,0,2,1,0,
3,1,2,3,1,3,0,2,1,0,1,0,0,1,2,2,3,2,3,1,3,2,1,1,2,0,2,1,3,3,1,0,
},
{1,2,3,4,5,6},
{4,6}
},
},
{ // 3rd round
{
{
0,3,0,1,0,2,3,3,1,0,1,3,2,2,1,1,3,3,3,0,2,0,2,0,0,0,2,3,1,1,0,0,
3,3,0,3,3,0,0,2,1,1,1,0,2,2,2,0,3,0,3,1,2,2,0,3,0,0,3,2,0,3,2,1,
},
{1,4,5,6,7,-1},
{0,5}
},
{
{
0,3,0,1,3,0,3,1,3,2,2,2,3,0,3,2,2,1,2,2,0,3,2,2,0,0,2,1,1,3,2,3,
2,3,3,1,2,0,1,2,2,1,0,0,0,0,2,3,1,2,0,3,1,3,1,2,3,2,1,0,3,0,0,2,
},
{0,2,3,4,6,7},
{1,7}
},
{
{
2,2,3,2,0,3,2,3,1,1,2,0,2,3,1,3,0,0,0,3,2,0,1,0,1,3,2,3,3,3,1,0,
// unused?
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
},
{1,2,4,7,-1,-1},
{2,4}
},
{
{
0,2,3,1,3,1,1,0,0,1,3,0,2,1,3,3,2,0,2,1,1,2,3,3,0,0,0,2,0,2,3,0,
3,3,3,3,2,3,3,2,3,0,1,0,2,3,3,2,0,1,3,1,0,1,2,3,3,0,2,0,3,0,3,3,
},
{0,1,2,3,5,7},
{3,6}
},
},
{ // 4th round
{
{
0,1,1,0,0,1,0,2,3,3,0,1,2,3,0,2,1,0,3,3,2,0,3,0,0,2,1,0,1,0,1,3,
0,3,3,1,2,0,3,0,1,3,2,0,3,3,1,3,0,2,3,3,2,1,1,2,2,1,2,1,2,0,1,1,
},
{0,1,2,4,7,-1},
{0,5}
},
{
{
2,0,0,2,3,0,2,3,3,1,1,1,2,1,1,0,0,2,1,0,0,3,1,0,0,3,3,0,1,0,1,2,
0,2,0,2,0,1,2,3,2,1,1,0,3,3,3,3,3,3,1,0,3,0,0,2,0,3,2,0,2,2,0,1,
},
{0,1,3,5,6,-1},
{1,3}
},
{
{
0,1,1,2,1,3,1,1,0,0,3,1,1,1,2,0,3,2,0,1,1,2,3,3,3,0,3,0,0,2,0,3,
3,2,0,0,3,2,3,1,2,3,0,3,2,0,1,2,2,2,0,2,0,1,2,2,3,1,2,2,1,1,1,1,
},
{0,2,3,4,5,7},
{2,7}
},
{
{
0,1,2,0,3,3,0,3,2,1,3,3,0,3,1,1,3,2,3,2,3,0,0,0,3,0,2,2,3,2,2,3,
2,2,3,1,2,3,1,2,0,3,0,2,3,1,0,0,3,2,1,2,1,2,1,3,1,0,2,3,3,1,3,2,
},
{2,3,4,5,6,7},
{4,6}
},
},
};
const int naomi_m2_board::fn1_game_key_scheduling[38][2] = {
{1,29}, {1,71}, {2,4}, {2,54}, {3,8}, {4,56}, {4,73}, {5,11},
{6,51}, {7,92}, {8,89}, {9,9}, {9,10}, {9,39}, {9,41}, {9,58},
{9,59}, {9,86}, {10,90}, {11,6}, {12,64}, {13,49}, {14,44}, {15,40},
{16,69}, {17,15}, {18,23}, {18,43}, {19,82}, {20,81}, {21,32}, {21,61},
{22,5}, {23,66}, {24,13}, {24,45}, {25,12}, {25,35}
};
const int naomi_m2_board::fn2_game_key_scheduling[34][2] = {
{0,0}, {1,3}, {2,11}, {3,20}, {4,22}, {5,23}, {6,29}, {7,38},
{8,39}, {9,47}, {9,55}, {9,86}, {9,87}, {9,90}, {10,50}, {10,53},
{11,57}, {12,59}, {13,61}, {13,64}, {14,63}, {15,67}, {16,72}, {17,83},
{18,88}, {19,94}, {20,35}, {21,17}, {21,92}, {22,6}, {22,11}, {23,85},
{24,16}, {25,25}
};
const int naomi_m2_board::fn1_sequence_key_scheduling[20][2] = {
{0,52}, {1,34}, {2,17}, {3,36}, {4,84}, {4,88}, {5,57}, {6,48},
{6,68}, {7,76}, {8,83}, {9,30}, {10,22}, {10,41}, {11,38}, {12,55},
{13,74}, {14,19}, {14,80}, {15,26}
};
const int naomi_m2_board::fn2_sequence_key_scheduling[16] = {77,34,8,42,36,27,69,66,13,9,79,31,49,7,24,64};
const int naomi_m2_board::fn2_middle_result_scheduling[16] = {1,10,44,68,74,78,81,95,2,4,30,40,41,51,53,58};
int naomi_m2_board::feistel_function(int input, const struct sbox *sboxes, UINT32 subkeys)
{
int k,m;
int aux;
int result=0;
for (m=0; m<4; ++m) { // 4 sboxes
for (k=0, aux=0; k<6; ++k)
if (sboxes[m].inputs[k]!=-1)
aux |= BIT(input, sboxes[m].inputs[k]) << k;
aux = sboxes[m].table[(aux^subkeys)&0x3f];
for (k=0; k<2; ++k)
result |= BIT(aux,k) << sboxes[m].outputs[k];
subkeys >>=6;
}
return result;
}
/**************************
This implementation is an "educational" version. It must be noted that it can be speed-optimized in a number of ways.
The most evident one is to factor out the parts of the key-scheduling that must only be done once (like the game-key &
sequence-key parts) as noted in the comments inlined in the function. More sophisticated speed-ups can be gained by
noticing that the weak key-scheduling would allow to create some pregenerated look-up tables for doing most of the work
of the function. Even so, it would still be pretty slow, so caching techniques could be a wiser option here.
**************************/
UINT16 naomi_m2_board::block_decrypt(UINT32 game_key, UINT16 sequence_key, UINT16 counter, UINT16 data)
{
int j;
int aux,aux2;
int A,B;
int middle_result;
UINT32 fn1_subkeys[4];
UINT32 fn2_subkeys[4];
/* Game-key scheduling; this could be done just once per game at initialization time */
memset(fn1_subkeys,0,sizeof(UINT32)*4);
memset(fn2_subkeys,0,sizeof(UINT32)*4);
for (j=0; j<38; ++j) {
if (BIT(game_key, fn1_game_key_scheduling[j][0])!=0) {
aux = fn1_game_key_scheduling[j][1]%24;
aux2 = fn1_game_key_scheduling[j][1]/24;
fn1_subkeys[aux2] ^= (1<<aux);
}
}
for (j=0; j<34; ++j) {
if (BIT(game_key, fn2_game_key_scheduling[j][0])!=0) {
aux = fn2_game_key_scheduling[j][1]%24;
aux2 = fn2_game_key_scheduling[j][1]/24;
fn2_subkeys[aux2] ^= (1<<aux);
}
}
/********************************************************/
/* Sequence-key scheduling; this could be done just once per decryption run */
for (j=0; j<20; ++j) {
if (BIT(sequence_key,fn1_sequence_key_scheduling[j][0])!=0) {
aux = fn1_sequence_key_scheduling[j][1]%24;
aux2 = fn1_sequence_key_scheduling[j][1]/24;
fn1_subkeys[aux2] ^= (1<<aux);
}
}
for (j=0; j<16; ++j) {
if (BIT(sequence_key,j)!=0) {
aux = fn2_sequence_key_scheduling[j]%24;
aux2 = fn2_sequence_key_scheduling[j]/24;
fn2_subkeys[aux2] ^= (1<<aux);
}
}
// subkeys bits 10 & 41
fn2_subkeys[0] ^= (BIT(sequence_key,2)<<10);
fn2_subkeys[1] ^= (BIT(sequence_key,4)<<17);
/**************************************************************/
// First Feistel Network
aux = BITSWAP16(counter,5,12,14,13,9,3,6,4, 8,1,15,11,0,7,10,2);
// 1st round
B = aux >> 8;
A = (aux & 0xff) ^ feistel_function(B,fn1_sboxes[0],fn1_subkeys[0]);
// 2nd round
B = B ^ feistel_function(A,fn1_sboxes[1],fn1_subkeys[1]);
// 3rd round
A = A ^ feistel_function(B,fn1_sboxes[2],fn1_subkeys[2]);
// 4th round
B = B ^ feistel_function(A,fn1_sboxes[3],fn1_subkeys[3]);
middle_result = (B<<8)|A;
/* Middle-result-key sheduling */
for (j=0; j<16; ++j) {
if (BIT(middle_result,j)!=0) {
aux = fn2_middle_result_scheduling[j]%24;
aux2 = fn2_middle_result_scheduling[j]/24;
fn2_subkeys[aux2] ^= (1<<aux);
}
}
/*********************/
// Second Feistel Network
aux = BITSWAP16(data,14,3,8,12,13,7,15,4, 6,2,9,5,11,0,1,10);
// 1st round
B = aux >> 8;
A = (aux & 0xff) ^ feistel_function(B,fn2_sboxes[0],fn2_subkeys[0]);
// 2nd round
B = B ^ feistel_function(A,fn2_sboxes[1],fn2_subkeys[1]);
// 3rd round
A = A ^ feistel_function(B,fn2_sboxes[2],fn2_subkeys[2]);
// 4th round
B = B ^ feistel_function(A,fn2_sboxes[3],fn2_subkeys[3]);
aux = (B<<8)|A;
aux = BITSWAP16(aux,15,7,6,14,13,12,5,4, 3,2,11,10,9,1,0,8);
return aux;
}
UINT16 naomi_m2_board::get_decrypted_16()
{
UINT16 enc;
if((prot_cur_address & 0xffff0000) == 0x01000000) {
int base = 2*(prot_cur_address & 0x7fff);
enc = ram[base+1] | (ram[base] << 8);
} else {
const UINT8 *base = m_region->base() + 2*prot_cur_address;
enc = base[1] | (base[0] << 8);
}
UINT16 dec = block_decrypt(key, subkey, prot_cur_address, enc);
UINT16 res = (dec & 3) | (dec_hist & 0xfffc);
dec_hist = dec;
prot_cur_address ++;
return res;
}
void naomi_m2_board::enc_start()
{
buffer_pos = BUFFER_SIZE;
dec_header = get_decrypted_16() << 16;
dec_header |= get_decrypted_16();
if(dec_header & FLAG_COMPRESSED) {
line_buffer_size = dec_header & FLAG_LINE_SIZE_512 ? 512 : 256;
line_buffer_pos = line_buffer_size;
buffer_bit = 7;
}
enc_ready = true;
}
void naomi_m2_board::enc_fill()
{
assert(buffer_pos == BUFFER_SIZE);
for(int i = 0; i != BUFFER_SIZE; i+=2) {
UINT16 val = get_decrypted_16();
buffer[i] = val;
buffer[i+1] = val >> 8;
}
buffer_pos = 0;
}
/* node format
0xxxxxxx - next node index
1a0bbccc - end node
a - 0 = repeat
1 = fetch
b - if a = 1
00 - fetch 0
01 - fetch 1
11 - fetch -1
if a = 0
000
c - repeat/fetch counter
count = ccc + 1
11111111 - empty node
*/
const UINT8 naomi_m2_board::trees[9][2][32] = {
{
{0x01,0x10,0x0f,0x05,0xc4,0x13,0x87,0x0a,0xcc,0x81,0xce,0x0c,0x86,0x0e,0x84,0xc2,
0x11,0xc1,0xc3,0xcf,0x15,0xc8,0xcd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
{0xc7,0x02,0x03,0x04,0x80,0x06,0x07,0x08,0x09,0xc9,0x0b,0x0d,0x82,0x83,0x85,0xc0,
0x12,0xc6,0xc5,0x14,0x16,0xca,0xcb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
},
{
{0x02,0x80,0x05,0x04,0x81,0x10,0x15,0x82,0x09,0x83,0x0b,0x0c,0x0d,0xdc,0x0f,0xde,
0x1c,0xcf,0xc5,0xdd,0x86,0x16,0x87,0x18,0x19,0x1a,0xda,0xca,0xc9,0x1e,0xce,0xff,},
{0x01,0x17,0x03,0x0a,0x08,0x06,0x07,0xc2,0xd9,0xc4,0xd8,0xc8,0x0e,0x84,0xcb,0x85,
0x11,0x12,0x13,0x14,0xcd,0x1b,0xdb,0xc7,0xc0,0xc1,0x1d,0xdf,0xc3,0xc6,0xcc,0xff,},
},
{
{0xc6,0x80,0x03,0x0b,0x05,0x07,0x82,0x08,0x15,0xdc,0xdd,0x0c,0xd9,0xc2,0x14,0x10,
0x85,0x86,0x18,0x16,0xc5,0xc4,0xc8,0xc9,0xc0,0xcc,0xff,0xff,0xff,0xff,0xff,0xff,},
{0x01,0x02,0x12,0x04,0x81,0x06,0x83,0xc3,0x09,0x0a,0x84,0x11,0x0d,0x0e,0x0f,0x19,
0xca,0xc1,0x13,0xd8,0xda,0xdb,0x17,0xde,0xcd,0xcb,0xff,0xff,0xff,0xff,0xff,0xff,},
},
{
{0x01,0x80,0x0d,0x04,0x05,0x15,0x83,0x08,0xd9,0x10,0x0b,0x0c,0x84,0x0e,0xc0,0x14,
0x12,0xcb,0x13,0xca,0xc8,0xc2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
{0xc5,0x02,0x03,0x07,0x81,0x06,0x82,0xcc,0x09,0x0a,0xc9,0x11,0xc4,0x0f,0x85,0xd8,
0xda,0xdb,0xc3,0xdc,0xdd,0xc1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
},
{
{0x01,0x80,0x06,0x0c,0x05,0x81,0xd8,0x84,0x09,0xdc,0x0b,0x0f,0x0d,0x0e,0x10,0xdb,
0x11,0xca,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
{0xc4,0x02,0x03,0x04,0xcb,0x0a,0x07,0x08,0xd9,0x82,0xc8,0x83,0xc0,0xc1,0xda,0xc2,
0xc9,0xc3,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
},
{
{0x01,0x02,0x06,0x0a,0x83,0x0b,0x07,0x08,0x09,0x82,0xd8,0x0c,0xd9,0xda,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
{0xc3,0x80,0x03,0x04,0x05,0x81,0xca,0xc8,0xdb,0xc9,0xc0,0xc1,0x0d,0xc2,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
},
{
{0x01,0x02,0x03,0x04,0x81,0x07,0x08,0xd8,0xda,0xd9,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
{0xc2,0x80,0x05,0xc9,0xc8,0x06,0x82,0xc0,0x09,0xc1,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
},
{
{0x01,0x80,0x04,0xc8,0xc0,0xd9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
{0xc1,0x02,0x03,0x81,0x05,0xd8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
},
{
{0x01,0xd8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
{0xc0,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
},
};
int naomi_m2_board::get_compressed_bit()
{
if(buffer_pos == BUFFER_SIZE)
enc_fill();
int res = (buffer[buffer_pos^1] >> buffer_bit) & 1;
buffer_bit--;
if(buffer_bit == -1) {
buffer_bit = 7;
buffer_pos++;
}
return res;
}
void naomi_m2_board::line_fill()
{
assert(line_buffer_pos == line_buffer_size);
UINT8 *lp = line_buffer;
UINT8 *lc = line_buffer_prev;
line_buffer = lc;
line_buffer_prev = lp;
line_buffer_pos = 0;
UINT32 line_buffer_mask = line_buffer_size-1;
for(int i=0; i != line_buffer_size;) {
// vlc 0: start of line
// vlc 1: interior of line
// vlc 2-9: 7-1 bytes from end of line
int slot = i ? i < line_buffer_size - 7 ? 1 : (i & 7) + 1 : 0;
UINT32 tmp = 0;
while (!(tmp&0x80))
if(get_compressed_bit())
tmp = trees[slot][1][tmp];
else
tmp = trees[slot][0][tmp];
if(tmp != 0xff) {
int count = (tmp & 7) + 1;
if(tmp&0x40) {
// Copy from previous line
static int offsets[4] = {0, 1, 0, -1};
int offset = offsets[(tmp & 0x18) >> 3];
for(int j=0; j != count; j++) {
lc[i^1] = lp[((i+offset) & line_buffer_mask)^1];
i++;
}
} else {
// Get a byte in the stream and write n times
UINT8 byte;
byte = get_compressed_bit() << 1;
byte = (byte | get_compressed_bit()) << 1;
byte = (byte | get_compressed_bit()) << 1;
byte = (byte | get_compressed_bit()) << 1;
byte = (byte | get_compressed_bit()) << 1;
byte = (byte | get_compressed_bit()) << 1;
byte = (byte | get_compressed_bit()) << 1;
byte = byte | get_compressed_bit();
for(int j=0; j != count; j++)
lc[(i++)^1] = byte;
}
}
}
}

View File

@ -0,0 +1,73 @@
#ifndef _NAOMIM2_H_
#define _NAOMIM2_H_
#include "naomibd.h"
#define MCFG_NAOMI_M2_BOARD_ADD(_tag, _key_tag, _eeprom_tag, _maincpu_tag, _irq_cb) \
MCFG_NAOMI_BOARD_ADD(_tag, NAOMI_M2_BOARD, _eeprom_tag, _maincpu_tag, _irq_cb) \
naomi_m2_board::static_set_tags(*device, _key_tag);
class naomi_m2_board : public naomi_board
{
public:
naomi_m2_board(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
static void static_set_tags(device_t &device, const char *_key_tag);
protected:
virtual void device_start();
virtual void device_reset();
virtual void board_setup_address(UINT32 address, bool is_dma);
virtual void board_get_buffer(UINT8 *&base, UINT32 &limit);
virtual void board_advance(UINT32 size);
virtual void board_write(offs_t offset, UINT16 data);
private:
enum {
RAM_SIZE = 65536, BUFFER_SIZE = 32768, LINE_SIZE = 512,
FLAG_COMPRESSED = 0x10000, FLAG_LINE_SIZE_512 = 0x20000
};
const char *key_tag;
UINT32 key;
UINT8 *ram, *buffer, *line_buffer, *line_buffer_prev;
UINT32 rom_cur_address, prot_cur_address;
UINT16 subkey, dec_hist;
UINT32 dec_header;
bool enc_ready;
int buffer_pos, line_buffer_pos, line_buffer_size, buffer_bit;
struct sbox {
UINT8 table[64];
int inputs[6]; // positions of the inputs bits, -1 means no input except from key
int outputs[2]; // positions of the output bits
};
static const sbox fn1_sboxes[4][4];
static const sbox fn2_sboxes[4][4];
static const int fn1_game_key_scheduling[38][2];
static const int fn2_game_key_scheduling[34][2];
static const int fn1_sequence_key_scheduling[20][2];
static const int fn2_sequence_key_scheduling[16];
static const int fn2_middle_result_scheduling[16];
static const UINT8 trees[9][2][32];
int feistel_function(int input, const struct sbox *sboxes, UINT32 subkeys);
UINT16 block_decrypt(UINT32 game_key, UINT16 sequence_key, UINT16 counter, UINT16 data);
UINT16 get_decrypted_16();
int get_compressed_bit();
void enc_start();
void enc_fill();
void line_fill();
};
extern const device_type NAOMI_M2_BOARD;
#endif

View File

@ -0,0 +1,165 @@
#define ADDRESS_MAP_MODERN
#include "emu.h"
#include "naomim4.h"
// Decoder for M4-type NAOMI cart encryption
// In hardware, the decryption is managed by the XC3S50 Xilinx Spartan FPGA (IC2)
// and the annexed PIC16C621A PIC MCU (IC3).
// - The FPGA control the clock line of the security PIC.
// - The protocol between the FPGA and the MCU is nibble-based, though it hasn't been RE for now.
// - The decryption algorithm is clearly nibble-based too.
// The decryption algorithm itself implements a stream cipher built on top of a 16-bits block cipher.
// The underlying block-cipher is a SP-network of 2 rounds (both identical in structure). In every
// round, the substitution phase is done using 4 fixed 4-to-4 sboxes acting on every nibble. The permutation
// phase is indeed a nibble-based linear combination.
// With that block cipher, a stream cipher is constructed by feeding the output result of the 1st round
// of a certain 16-bits block as a whitening value for the next block. The cart dependent data used by
// the algorithm is comprised by a 16-bits "key" and a 16-bits IV (initialization vector) --though they
// will be merged in a only 32-bits number in the code--. The hardware auto-reset the feed value
// to the cart-based IV every 16 blocks (32 bytes); that reset is not address-based, but index-based.
const device_type NAOMI_M4_BOARD = &device_creator<naomi_m4_board>;
const UINT8 naomi_m4_board::k_sboxes[4][16] = {
{13,14,1,11,7,9,10,0,15,6,4,5,8,2,12,3},
{12,3,14,6,7,15,2,13,1,4,11,0,9,10,8,5},
{6,12,0,10,1,5,14,9,7,2,15,13,4,11,3,8},
{9,12,8,7,10,4,0,15,1,11,14,2,13,5,6,3}
};
naomi_m4_board::naomi_m4_board(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: naomi_board(mconfig, NAOMI_M4_BOARD, "NAOMI-M1-BOARD", tag, owner, clock)
{
key_tag = 0;
}
void naomi_m4_board::static_set_tags(device_t &device, const char *_key_tag)
{
naomi_m4_board &dev = downcast<naomi_m4_board &>(device);
dev.key_tag = _key_tag;
}
void naomi_m4_board::device_start()
{
naomi_board::device_start();
const UINT8 *key_data = machine().region(key_tag)->base();
key = (key_data[2] << 8) | key_data[3];
iv = (key_data[0] << 8) | key_data[1];
buffer = auto_alloc_array(machine(), UINT8, BUFFER_SIZE);
enc_init();
save_pointer(NAME(buffer), BUFFER_SIZE);
save_item(NAME(rom_cur_address));
save_item(NAME(buffer_actual_size));
save_item(NAME(encryption));
save_item(NAME(counter));
}
void naomi_m4_board::enc_init()
{
one_round = auto_alloc_array(machine(), UINT16, 0x10000);
for(int round_input = 0; round_input < 0x10000; round_input++) {
UINT8 input_nibble[4];
UINT8 output_nibble[4];
for (int nibble_idx = 0; nibble_idx < 4; ++nibble_idx) {
input_nibble[nibble_idx] = (round_input >> (nibble_idx*4)) & 0xf;
output_nibble[nibble_idx] = 0;
}
UINT8 aux_nibble = input_nibble[3];
for (int nibble_idx = 0; nibble_idx < 4; ++nibble_idx) { // 4 s-boxes per round
aux_nibble ^= k_sboxes[nibble_idx][input_nibble[nibble_idx]];
for (int i = 0; i < 4; ++i) // diffusion of the bits
output_nibble[(nibble_idx - i) & 3] |= aux_nibble & (1 << i);
}
UINT16 result = 0;
for (int nibble_idx = 0; nibble_idx < 4; ++nibble_idx)
result |= (output_nibble[nibble_idx] << (4 * nibble_idx));
one_round[round_input] = result;
}
}
void naomi_m4_board::device_reset()
{
naomi_board::device_reset();
rom_cur_address = 0;
buffer_actual_size = 0;
encryption = false;
counter = 0;
cur_iv = 0;
}
void naomi_m4_board::board_setup_address(UINT32 address, bool is_dma)
{
rom_cur_address = address & 0x1fffffff;
encryption = !(address & 0x20000000);
if(encryption) {
enc_reset();
enc_fill();
}
}
void naomi_m4_board::board_get_buffer(UINT8 *&base, UINT32 &limit)
{
if(encryption) {
base = buffer;
limit = BUFFER_SIZE;
} else {
base = m_region->base() + rom_cur_address;
limit = m_region->bytes() - rom_cur_address;
}
}
void naomi_m4_board::board_advance(UINT32 size)
{
if(encryption) {
if(size < buffer_actual_size) {
memmove(buffer, buffer + size, buffer_actual_size - size);
buffer_actual_size -= size;
} else
buffer_actual_size = 0;
enc_fill();
} else
rom_cur_address += size;
}
void naomi_m4_board::enc_reset()
{
buffer_actual_size = 0;
cur_iv = iv;
counter = 0;
}
void naomi_m4_board::enc_fill()
{
const UINT8 *base = m_region->base() + rom_cur_address;
while(buffer_actual_size < BUFFER_SIZE) {
UINT16 enc = base[0] | (base[1] << 8);
UINT16 output_whitening = key ^ cur_iv;
cur_iv = one_round[enc ^ cur_iv];
UINT16 dec = one_round[key ^ cur_iv] ^ output_whitening;
buffer[buffer_actual_size++] = dec;
buffer[buffer_actual_size++] = dec >> 8;
base += 2;
rom_cur_address += 2;
counter++;
if(counter == 16) {
counter = 0;
cur_iv = iv;
}
}
}

View File

@ -0,0 +1,47 @@
#ifndef _NAOMIM4_H_
#define _NAOMIM4_H_
#include "naomibd.h"
#define MCFG_NAOMI_M4_BOARD_ADD(_tag, _key_tag, _eeprom_tag, _maincpu_tag, _irq_cb) \
MCFG_NAOMI_BOARD_ADD(_tag, NAOMI_M4_BOARD, _eeprom_tag, _maincpu_tag, _irq_cb) \
naomi_m4_board::static_set_tags(*device, _key_tag);
class naomi_m4_board : public naomi_board
{
public:
naomi_m4_board(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
static void static_set_tags(device_t &device, const char *_key_tag);
protected:
virtual void device_start();
virtual void device_reset();
virtual void board_setup_address(UINT32 address, bool is_dma);
virtual void board_get_buffer(UINT8 *&base, UINT32 &limit);
virtual void board_advance(UINT32 size);
private:
enum { BUFFER_SIZE = 32768 };
static const UINT8 k_sboxes[4][16];
const char *key_tag;
UINT16 key, iv;
UINT16 *one_round;
UINT8 *buffer;
UINT32 rom_cur_address, buffer_actual_size;
UINT16 cur_iv;
UINT8 counter;
bool encryption;
void enc_init();
void enc_reset();
void enc_fill();
};
extern const device_type NAOMI_M4_BOARD;
#endif

View File

@ -1,73 +0,0 @@
#include "naomim4decoder.h"
const UINT8 NaomiM4Decoder::k_sboxes[4][16] = {
{13,14,1,11,7,9,10,0,15,6,4,5,8,2,12,3},
{12,3,14,6,7,15,2,13,1,4,11,0,9,10,8,5},
{6,12,0,10,1,5,14,9,7,2,15,13,4,11,3,8},
{9,12,8,7,10,4,0,15,1,11,14,2,13,5,6,3}
};
NaomiM4Decoder::NaomiM4Decoder(UINT32 cart_key)
: m_key(cart_key & 0xffff)
, m_iv(cart_key >> 16) // initialization vector
{
m_one_round = global_alloc_array(UINT16,0x10000);
// populate the lookup table for one of the internal rounds of the cipher
for (UINT32 i=0; i<0x10000; ++i)
{
m_one_round[i] = one_round_core(i);
}
}
NaomiM4Decoder::~NaomiM4Decoder()
{
global_free(m_one_round);
}
void NaomiM4Decoder::init()
{
m_counter = 0;
}
UINT16 NaomiM4Decoder::decrypt(UINT16 ciphertext) // decrypt the next 16-bits value in the stream
{
if (0 == (m_counter++ & 0xf)) // the iv is recovered every 16 values (32 bytes)
m_middle_value = m_iv;
UINT16 output_whitening = m_key ^ m_middle_value;
m_middle_value = m_one_round[ciphertext ^ m_middle_value];
return m_one_round[m_middle_value ^ m_key] ^ output_whitening;
}
UINT16 NaomiM4Decoder::one_round_core(UINT16 round_input)
{
UINT8 input_nibble[4];
UINT8 output_nibble[4];
UINT8 aux_nibble;
UINT8 nibble_idx;
UINT8 i;
UINT16 result;
for (nibble_idx = 0; nibble_idx < 4; ++nibble_idx, round_input >>= 4)
{
input_nibble[nibble_idx] = round_input & 0xf;
output_nibble[nibble_idx] = 0;
}
aux_nibble = input_nibble[3];
for (nibble_idx = 0; nibble_idx < 4; ++nibble_idx) // 4 s-boxes per round
{
aux_nibble ^= k_sboxes[nibble_idx][input_nibble[nibble_idx]];
for (i = 0; i < 4; ++i) // diffusion of the bits
output_nibble[(nibble_idx - i) & 3] |= aux_nibble & (1 << i);
}
for (nibble_idx = 0, result = 0; nibble_idx < 4; ++nibble_idx)
result |= (output_nibble[nibble_idx] << (4 * nibble_idx));
return result;
}

View File

@ -1,46 +0,0 @@
#pragma once
#ifndef __NAOMIM4DECODER_H__
#define __NAOMIM4DECODER_H__
#include "emu.h"
// Decoder for M4-type NAOMI cart encryption
// In hardware, the decryption is managed by the XC3S50 Xilinx Spartan FPGA (IC2)
// and the annexed PIC16C621A PIC MCU (IC3).
// - The FPGA control the clock line of the security PIC.
// - The protocol between the FPGA and the MCU is nibble-based, though it hasn't been RE for now.
// - The decryption algorithm is clearly nibble-based too.
// The decryption algorithm itself implements a stream cipher built on top of a 16-bits block cipher.
// The underlying block-cipher is a SP-network of 2 rounds (both identical in structure). In every
// round, the substitution phase is done using 4 fixed 4-to-4 sboxes acting on every nibble. The permutation
// phase is indeed a nibble-based linear combination.
// With that block cipher, a stream cipher is constructed by feeding the output result of the 1st round
// of a certain 16-bits block as a whitening value for the next block. The cart dependent data used by
// the algorithm is comprised by a 16-bits "key" and a 16-bits IV (initialization vector) --though they
// will be merged in a only 32-bits number in the code--. The hardware auto-reset the feed value
// to the cart-based IV every 16 blocks (32 bytes); that reset is not address-based, but index-based.
class NaomiM4Decoder
{
public:
NaomiM4Decoder(UINT32 cart_key);
~NaomiM4Decoder();
void init(); // initialize the decryption of a new stream (set the IV)
UINT16 decrypt(UINT16 ciphertext); // decrypt the next 16-bits value in the stream
private:
UINT16 one_round_core(UINT16 round_input);
static const UINT8 k_sboxes[4][16];
UINT16 *m_one_round;
const UINT16 m_key;
const UINT16 m_iv;
UINT16 m_middle_value; // used by the stream cipher as feeding to the next block
UINT8 m_counter;
};
#endif // __NAOMIM4DECODER_H__

View File

@ -0,0 +1,40 @@
#define ADDRESS_MAP_MODERN
#include "emu.h"
#include "naomirom.h"
const device_type NAOMI_ROM_BOARD = &device_creator<naomi_rom_board>;
naomi_rom_board::naomi_rom_board(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: naomi_board(mconfig, NAOMI_ROM_BOARD, "NAOMI-ROM-BOARD", tag, owner, clock)
{
}
void naomi_rom_board::device_start()
{
naomi_board::device_start();
save_item(NAME(rom_cur_address));
}
void naomi_rom_board::device_reset()
{
naomi_board::device_reset();
rom_cur_address = 0;
}
void naomi_rom_board::board_setup_address(UINT32 address, bool is_dma)
{
rom_cur_address = address & 0x1fffffff;
}
void naomi_rom_board::board_get_buffer(UINT8 *&base, UINT32 &limit)
{
base = m_region->base() + rom_cur_address;
limit = m_region->bytes() - rom_cur_address;
}
void naomi_rom_board::board_advance(UINT32 size)
{
rom_cur_address += size;
}

View File

@ -0,0 +1,28 @@
#ifndef _NAOMIROM_H_
#define _NAOMIROM_H_
#include "naomibd.h"
#define MCFG_NAOMI_ROM_BOARD_ADD(_tag, _eeprom_tag, _maincpu_tag, _irq_cb) \
MCFG_NAOMI_BOARD_ADD(_tag, NAOMI_ROM_BOARD, _eeprom_tag, _maincpu_tag, _irq_cb)
class naomi_rom_board : public naomi_board
{
public:
naomi_rom_board(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
protected:
virtual void device_start();
virtual void device_reset();
virtual void board_setup_address(UINT32 address, bool is_dma);
virtual void board_get_buffer(UINT8 *&base, UINT32 &limit);
virtual void board_advance(UINT32 size);
private:
UINT32 rom_cur_address;
};
extern const device_type NAOMI_ROM_BOARD;
#endif

View File

@ -1191,9 +1191,9 @@ $(MAMEOBJ)/sega.a: \
$(DRIVERS)/model1.o $(MACHINE)/model1.o $(VIDEO)/model1.o \
$(DRIVERS)/model2.o $(VIDEO)/model2.o \
$(DRIVERS)/model3.o $(VIDEO)/model3.o $(MACHINE)/model3.o \
$(DRIVERS)/naomi.o $(MACHINE)/dc.o $(VIDEO)/dc.o $(MACHINE)/gdcrypt.o $(MACHINE)/naomibd.o $(MACHINE)/naomi.o $(MACHINE)/naomim4decoder.o\
$(MACHINE)/mie.o $(MACHINE)/maple-dc.o $(MACHINE)/mapledev.o $(MACHINE)/dc-ctrl.o \
$(MACHINE)/jvs13551.o \
$(DRIVERS)/naomi.o $(MACHINE)/dc.o $(VIDEO)/dc.o $(MACHINE)/naomi.o \
$(MACHINE)/naomig1.o $(MACHINE)/naomibd.o $(MACHINE)/naomirom.o $(MACHINE)/naomigd.o $(MACHINE)/naomim1.o $(MACHINE)/naomim2.o $(MACHINE)/naomim4.o $(MACHINE)/awboard.o \
$(MACHINE)/mie.o $(MACHINE)/maple-dc.o $(MACHINE)/mapledev.o $(MACHINE)/dc-ctrl.o $(MACHINE)/jvs13551.o \
$(DRIVERS)/triforce.o \
$(DRIVERS)/puckpkmn.o \
$(DRIVERS)/segac2.o \