mirror of
https://github.com/holub/mame
synced 2025-07-15 06:27:46 +03:00
naomi: Split the rom boards into a collection of devices. [O. Galibert]
This commit is contained in:
parent
ca3a17ace0
commit
2393deea86
4
.gitattributes
vendored
4
.gitattributes
vendored
@ -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
|
||||
|
@ -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) \
|
||||
|
@ -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
@ -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) \
|
||||
|
@ -44,3 +44,5 @@ extern UINT64 *naomi_ram64;
|
||||
|
||||
extern int jvsboard_type;
|
||||
extern UINT16 actel_id;
|
||||
|
||||
void naomi_g1_irq(running_machine &machine);
|
||||
|
@ -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);
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
@ -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;
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
@ -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
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
@ -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;
|
||||
}
|
@ -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
|
@ -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;
|
||||
}
|
@ -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
|
@ -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;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
@ -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;
|
||||
}
|
||||
|
@ -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__
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
@ -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 \
|
||||
|
Loading…
Reference in New Issue
Block a user