69
49
Or it could really be the last address bit to allow up to 512MB of data on a cart?
71
51
Normal address starts with 0xa0000000 to enable auto-advance and standard addressing mode.
73
------------------------
75
Atomiswave ROM board specs from Cah4e3 @ http://cah4e3.wordpress.com/2009/07/26/some-atomiswave-info/
77
AW_EPR_OFFSETL Register addres: 0x5f7000
78
+-------------------------------------------------------------------------------+
80
+-------------------------------------------------------------------------------+
81
| EPR data offset low word |
82
+-------------------------------------------------------------------------------+
84
AW_EPR_OFFSETH Register addres: 0x5f7004
85
+-------------------------------------------------------------------------------+
87
+-------------------------------------------------------------------------------+
88
| EPR data offset hi word |
89
+-------------------------------------------------------------------------------+
91
Both low and high words of 32-bit offset from start of EPR-ROM area. Used for
92
reading header and programm code data, cannot be used for reading MPR-ROMs data.
94
AW_MPR_RECORD_INDEX Register addres: 0x5f700c
95
+-------------------------------------------------------------------------------+
97
+-------------------------------------------------------------------------------+
98
| File system record index |
99
+-------------------------------------------------------------------------------+
101
This register contains index of MPR-ROM file system record (64-bytes in size) to
102
read throught DMA. Internal DMA offset register is assigned as AW_MPR_RECORD_INDEX<<6
103
from start of MPR-ROM area. Size of DMA transaction not limited, it is possible
104
to read any number of records or just part of it.
106
AW_MPR_FIRST_FILE_INDEX Register addres: 0x5f7010
107
+-------------------------------------------------------------------------------+
109
+-------------------------------------------------------------------------------+
110
| First file record index |
111
+-------------------------------------------------------------------------------+
113
This register assign for internal cart circuit index of record in MPR-ROM file
114
system sub-area that contain information about first file of MPR-ROM files
115
sub-area. Internal circuit using this record to read absolute first file offset
116
from start of MPR-ROM area and calculate normal offset for each other file
117
requested, since MPR-ROM file data sub-area can be assighed only with relative
118
offsets from start of such sub-area.
120
AW_MPR_FILE_OFFSETL Register addres: 0x5f7014
121
+-------------------------------------------------------------------------------+
123
+-------------------------------------------------------------------------------+
124
| MPR file offset low word |
125
+-------------------------------------------------------------------------------+
127
AW_MPR_FILE_OFFSETH Register addres: 0x5f7018
128
+-------------------------------------------------------------------------------+
130
+-------------------------------------------------------------------------------+
131
| MPR file offset hi word |
132
+-------------------------------------------------------------------------------+
134
Both low and high words of 32-bit relative offset from start of MPR-ROM files
135
sub-area. Used by internal circuit to calculate absolute offset using data
136
from AW_MPR_FIRST_FILE_INDEX register. Cannot be used for reading EPR-ROM
137
data nor even MPR-ROM file system sub-area data.
142
+--------------+ 0x00000000
144
| HEADER +- AW_EPR_OFFSET << 1
148
| CODE +- AW_EPR_OFFSET << 1
151
+--------------+ 0x007fffff
154
+--------------+ 0x00000000
156
| FS_RECORD[1] +- (AW_MPR_RECORD_INDEX << 6)
158
| FS_RECORD[3] +- (AW_MPR_FIRST_FILE_INDEX << 6)
161
+--------------+- FS_RECORD[AW_MPR_FIRST_FILE_INDEX].FILE_ABS_OFFSET
163
| FILE_1 +- (AW_MPR_FILE_OFFSET << 1) + FS_RECORD[AW_MPR_FIRST_FILE_INDEX].FILE_ABS_OFFSET
166
+--------------+ 0x07ffffff
170
// NOTE: all accesses are 16 or 32 bits wide but only 16 bits are valid
173
#include "profiler.h"
174
#include "machine/x76f100.h"
176
#include "includes/naomi.h"
177
#include "includes/naomibd.h"
179
#define NAOMIBD_FLAG_AUTO_ADVANCE (8) // address auto-advances on read
180
#define NAOMIBD_FLAG_SPECIAL_MODE (4) // used to access protection registers
181
#define NAOMIBD_FLAG_DMA_COMPRESSION (2) // 0 protection chip decompresses DMA data, 1 for normal DMA reads
183
#define NAOMIBD_PRINTF_PROTECTION (0) // 1 to printf protection access details
185
/*************************************
189
*************************************/
191
#define PACK_BUF_SIZE (32768)
200
typedef struct _naomibd_config_table naomibd_config_table;
201
struct _naomibd_config_table
208
typedef struct _naomibd_prot naomibd_prot;
211
UINT16 last_word, aux_word, pak_word, heading_word;
213
int count, pak_bit, control_bits, pak_state, dec_count, pak_buf_size, pak_buf_pos;
215
UINT8 pak_byte, cmd_byte;
217
UINT8 pak_buf[PACK_BUF_SIZE];
222
int s_subst, s_out_len, s_out_cnt, s_shift, s_bits, s_in_len, s_in_pos;
225
typedef struct _naomibd_state naomibd_state;
226
struct _naomibd_state
228
UINT8 index; /* index of board */
230
device_t *device; /* pointer to our containing device */
235
UINT32 rom_offset, rom_offset_flags, dma_count;
236
UINT32 dma_offset, dma_offset_flags;
237
UINT32 prot_offset, prot_key;
238
UINT32 aw_offset, aw_file_base, aw_file_offset;
241
UINT32 dc_gamekey, dc_seqkey, dc_dmakey;
242
UINT8 dc_cart_ram[256*1024]; // internal cartridge RAM
248
// maps protection offsets to real addresses
249
// format of array: encryption key, address written, address to switch out with. if key is -1 it's ignored and address written is the match.
250
// if key is not -1, it's used for the match instead of the address written.
251
static const naomibd_config_table naomibd_translate_tbl[] =
253
// games where on-the-fly decryption works (many of these are fully playable in MAME, just slow)
254
{ "18wheelr", 0x07cf54, 0 },
255
{ "alpilota", 0x070e41, 0 },
256
{ "alpiltdx", 0x070e41, 0 },
259
{ "crackndj", 0x1c2347, 0 },
260
{ "crzytaxi", 0x0d2f45, 0 },
261
{ "csmash", 0x103347, 0 },
262
{ "csmasho", 0x103347, 0 },
263
{ "cspike", 0x0e2010, 0 },
264
{ "deathcox", 0x0b64d0, 0 },
265
{ "derbyoc", 0x0fee35, 0 },
266
{ "doa2", 0x8ad01, 0 },
267
{ "doa2m", 0x8ad01, 0 },
268
{ "dybb99", 0x048a01, 0 },
269
{ "f355twin", 0x06efd4, 0 },
270
{ "f355twn2", 0x1666c6, 0 },
271
{ "ggram2", 0x074a61, 0 },
272
{ "ggx", 0x076110, 0 },
273
{ "gram2000", 0, 0x7f805c3f },
274
{ "gundmct", 0x0e8010, 0 },
275
{ "gwing2", 0x0b25d0, 0 },
276
{ "hmgeo", 0x038510, 0 },
277
{ "jambo", 0x0fab95, 0 },
278
{ "kick4csh", 0, 0x820857c9 },
279
{ "mvsc2", 0, 0xc18b6e7c },
280
{ "otrigger", 0x0fea94, 0 },
281
{ "pjustic", 0x0725d0, 0 },
282
{ "pstone", 0x0e69c1, 0 },
283
{ "pstone2", 0x0b8dc0, 0 },
284
{ "puyoda", 0x0acd40, 0 },
285
{ "qmegamis", 0, 0xcd9b4896 },
286
{ "ringout", 0x0b1e40, 0 },
287
{ "samba", 0x0a8b5d, 0 },
288
{ "samba2k", 0x1702cf, 0 },
289
{ "sgtetris", 0x8ae51, 0 },
290
{ "shootopl", 0, 0xa0f37ca7 },
291
{ "shootpl", 0, 0x9d8de9cd },
292
{ "shootplm", 0, 0x9d8de9cd },
293
{ "slasho", 0x1a66ca, 0 },
294
{ "smlg99", 0x048a01, 0 },
295
{ "spawn", 0x078d01, 0 },
296
{ "sstrkfgt", 0x132303, 0 },
297
{ "suchie3", 0x0368e1, 0 },
298
{ "toyfight", 0x02ca85, 0 },
299
{ "vf4cart", 0x2ef2f96, 0 },
300
{ "vf4evoct", 0, 0x1e5bb0cd },
301
{ "virnbao", 0x68b58, 0 }, // note: "virnba" set doesn't have protection
302
{ "vs2_2k", 0x88b08, 0 },
303
{ "vtennis", 0x03eb15, 0 },
304
{ "vtenis2c", 0, 0x2d2d4743 },
305
{ "vonot", 0x010715, 0 },
306
{ "wldkicks", 0xae2901, 0 },
307
{ "wwfroyal", 0x1627c3, 0 },
308
{ "zerogu2", 0x07c010, 0 },
309
{ "zombrvn", 0x012b41, 0 },
312
// forward declaration for decrypt function
313
static UINT16 block_decrypt(UINT32 game_key, UINT16 sequence_key, UINT16 counter, UINT16 data);
315
/***************************************************************************
317
***************************************************************************/
319
/*-------------------------------------------------
320
get_safe_token - makes sure that the passed
321
in device is, in fact, a naomibd device
322
-------------------------------------------------*/
324
INLINE naomibd_state *get_safe_token(device_t *device)
326
assert(device != NULL);
327
assert(device->type() == NAOMI_BOARD);
329
return (naomibd_state *)downcast<legacy_device_base *>(device)->token();
334
/*************************************
338
*************************************/
340
int naomibd_interrupt_callback(device_t *device, naomibd_interrupt_func callback)
342
naomibd_config *config = (naomibd_config *)downcast<const legacy_device_base *>(device)->inline_config();
343
config->interrupt = callback;
347
int naomibd_get_type(device_t *device)
349
naomibd_state *v = get_safe_token(device);
353
// M1 decryption/decompression
354
static UINT8 naomibd_m1dec_readbyte(naomibd_state *naomibd)
358
switch (naomibd->prot.s_in_pos & 3)
361
v = naomibd->prot.s_input[naomibd->prot.s_in_pos + 3];
362
v ^= naomibd->prot.s_input[naomibd->prot.s_in_pos + 1];
366
v = naomibd->prot.s_input[naomibd->prot.s_in_pos + 1];
367
v ^= naomibd->prot.s_input[naomibd->prot.s_in_pos - 1];
371
v = naomibd->prot.s_input[naomibd->prot.s_in_pos - 1];
375
v = naomibd->prot.s_input[naomibd->prot.s_in_pos - 3];
379
v ^= naomibd->prot.s_xor[naomibd->prot.s_in_pos & 3];
380
naomibd->prot.s_in_pos++;
384
static void naomibd_m1dec_storebyte (naomibd_state *naomibd, UINT8 b)
386
if (naomibd->prot.s_subst && naomibd->prot.s_out_cnt >= 2)
388
b = naomibd->dc_cart_ram[naomibd->prot.s_out_cnt - 2] - b;
390
naomibd->dc_cart_ram[naomibd->prot.s_out_cnt] = b;
391
naomibd->prot.s_out_cnt++;
393
if (naomibd->prot.s_out_cnt >= (256*1024))
395
fatalerror("naomibd: M1 decode exceeds buffer size!\n");
399
static void naomibd_m1dec_shiftin(naomibd_state *naomibd)
401
naomibd->prot.s_shift <<= 8;
402
naomibd->prot.s_shift |= naomibd_m1dec_readbyte(naomibd);
403
naomibd->prot.s_bits += 8;
406
static void naomibd_m1_decode(naomibd_state *naomibd)
410
naomibd->prot.s_xor [0] = (UINT8)naomibd->dc_dmakey;
411
naomibd->prot.s_xor [1] = (UINT8)(naomibd->dc_dmakey >> 8);
412
naomibd->prot.s_xor [2] = (UINT8)(naomibd->dc_dmakey >> 16);
413
naomibd->prot.s_xor [3] = (UINT8)(naomibd->dc_dmakey >> 24);
415
#if NAOMIBD_PRINTF_PROTECTION
416
printf("M1 decode: dma offset %x, key %x\n", naomibd->dma_offset, naomibd->dc_dmakey);
419
naomibd->prot.s_input = naomibd->memory + naomibd->dma_offset;
420
naomibd->prot.s_in_pos = 0;
422
// read in the dictionary
423
for (i = 0; i < 111; i++)
425
naomibd->prot.s_dict [i] = naomibd_m1dec_readbyte(naomibd);
429
naomibd->prot.s_subst = (naomibd->prot.s_dict [0] & 64) ? 1 : 0;
432
naomibd->prot.s_out_cnt = 0, eos = 0;
433
naomibd->prot.s_shift = 0, naomibd->prot.s_bits = 0;
438
if (naomibd->prot.s_bits < 2)
439
naomibd_m1dec_shiftin(naomibd);
441
code = (naomibd->prot.s_shift >> (naomibd->prot.s_bits - 2)) & 3;
446
if (naomibd->prot.s_bits < 4)
447
naomibd_m1dec_shiftin(naomibd);
448
addr = (naomibd->prot.s_shift >> (naomibd->prot.s_bits - 4)) & 3;
449
naomibd->prot.s_bits -= 4;
453
if (naomibd->prot.s_bits < 8)
454
naomibd_m1dec_shiftin (naomibd);
455
t = (naomibd->prot.s_shift >> (naomibd->prot.s_bits - 8)) & 255;
456
naomibd->prot.s_bits -= 8;
457
naomibd_m1dec_storebyte(naomibd, t);
460
naomibd_m1dec_storebyte(naomibd, naomibd->prot.s_dict [addr]);
464
if (naomibd->prot.s_bits < 5)
465
naomibd_m1dec_shiftin (naomibd);
466
t = (naomibd->prot.s_shift >> (naomibd->prot.s_bits - 3)) & 1;
470
addr = (naomibd->prot.s_shift >> (naomibd->prot.s_bits - 5)) & 3;
472
naomibd->prot.s_bits -= 5;
477
if (naomibd->prot.s_bits < 6)
478
naomibd_m1dec_shiftin (naomibd);
479
addr = (naomibd->prot.s_shift >> (naomibd->prot.s_bits - 6)) & 7;
481
naomibd->prot.s_bits -= 6;
483
naomibd_m1dec_storebyte(naomibd, naomibd->prot.s_dict [addr]);
487
if (naomibd->prot.s_bits < 7)
488
naomibd_m1dec_shiftin(naomibd);
490
addr = (naomibd->prot.s_shift >> (naomibd->prot.s_bits - 7)) & 31;
492
naomibd->prot.s_bits -= 7;
493
naomibd_m1dec_storebyte(naomibd, naomibd->prot.s_dict [addr]);
497
if (naomibd->prot.s_bits < 8)
498
naomibd_m1dec_shiftin(naomibd);
500
addr = (naomibd->prot.s_shift >> (naomibd->prot.s_bits - 8)) & 63;
502
naomibd->prot.s_bits -= 8;
510
naomibd_m1dec_storebyte(naomibd, naomibd->prot.s_dict [addr]);
517
// Streaming M2/M3 protection and decompression
519
INLINE UINT16 naomi_bswap16(UINT16 in)
521
return ((in>>8) | (in<<8));
524
static UINT16 naomibd_get_decrypted_stream(naomibd_state *naomibd)
526
UINT16 wordn = naomi_bswap16(naomibd->prot.ptr[naomibd->prot.count++]);
528
naomibd->prot.aux_word = block_decrypt(naomibd->dc_gamekey, naomibd->dc_seqkey, naomibd->prot.seed++, wordn);
529
wordn = (naomibd->prot.last_word&~3) | (naomibd->prot.aux_word&3);
530
naomibd->prot.last_word = naomibd->prot.aux_word;
535
static void naomibd_init_stream(naomibd_state *naomibd)
537
naomibd->prot.last_word = 0;
539
naomibd->prot.control_bits = naomibd_get_decrypted_stream(naomibd);
540
naomibd->prot.heading_word = naomibd_get_decrypted_stream(naomibd);
542
if (naomibd->prot.control_bits & 2)
544
naomibd->prot.pak_bit = 0;
545
naomibd->prot.pak_state = CMD_READY;
546
naomibd->prot.dec_count = 0;
547
naomibd->prot.pak_buf_size = 256 << (naomibd->prot.control_bits & 1);
548
naomibd->prot.pak_buf_pos = 0;
552
static UINT16 naomibd_get_compressed_bit(naomibd_state *naomibd)
554
if(naomibd->prot.pak_bit == 0)
556
naomibd->prot.pak_bit = 15;
557
naomibd->prot.pak_word = naomibd_get_decrypted_stream(naomibd);
561
naomibd->prot.pak_bit--;
562
naomibd->prot.pak_word<<=1;
564
return naomibd->prot.pak_word >> 15;
567
static UINT16 naomibd_get_decompressed_stream(naomibd_state *naomibd)
570
0xxxxxxx - next node index
580
c - repeat/fetch counter
582
11111111 - empty node
584
static UINT8 trees[9][2][32] = {
586
{0x01,0x10,0x0f,0x05,0xc4,0x13,0x87,0x0a,0xcc,0x81,0xce,0x0c,0x86,0x0e,0x84,0xc2,
587
0x11,0xc1,0xc3,0xcf,0x15,0xc8,0xcd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
588
{0xc7,0x02,0x03,0x04,0x80,0x06,0x07,0x08,0x09,0xc9,0x0b,0x0d,0x82,0x83,0x85,0xc0,
589
0x12,0xc6,0xc5,0x14,0x16,0xca,0xcb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
592
{0x02,0x80,0x05,0x04,0x81,0x10,0x15,0x82,0x09,0x83,0x0b,0x0c,0x0d,0xdc,0x0f,0xde,
593
0x1c,0xcf,0xc5,0xdd,0x86,0x16,0x87,0x18,0x19,0x1a,0xda,0xca,0xc9,0x1e,0xce,0xff,},
594
{0x01,0x17,0x03,0x0a,0x08,0x06,0x07,0xc2,0xd9,0xc4,0xd8,0xc8,0x0e,0x84,0xcb,0x85,
595
0x11,0x12,0x13,0x14,0xcd,0x1b,0xdb,0xc7,0xc0,0xc1,0x1d,0xdf,0xc3,0xc6,0xcc,0xff,},
598
{0xc6,0x80,0x03,0x0b,0x05,0x07,0x82,0x08,0x15,0xdc,0xdd,0x0c,0xd9,0xc2,0x14,0x10,
599
0x85,0x86,0x18,0x16,0xc5,0xc4,0xc8,0xc9,0xc0,0xcc,0xff,0xff,0xff,0xff,0xff,0xff,},
600
{0x01,0x02,0x12,0x04,0x81,0x06,0x83,0xc3,0x09,0x0a,0x84,0x11,0x0d,0x0e,0x0f,0x19,
601
0xca,0xc1,0x13,0xd8,0xda,0xdb,0x17,0xde,0xcd,0xcb,0xff,0xff,0xff,0xff,0xff,0xff,},
604
{0x01,0x80,0x0d,0x04,0x05,0x15,0x83,0x08,0xd9,0x10,0x0b,0x0c,0x84,0x0e,0xc0,0x14,
605
0x12,0xcb,0x13,0xca,0xc8,0xc2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
606
{0xc5,0x02,0x03,0x07,0x81,0x06,0x82,0xcc,0x09,0x0a,0xc9,0x11,0xc4,0x0f,0x85,0xd8,
607
0xda,0xdb,0xc3,0xdc,0xdd,0xc1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
610
{0x01,0x80,0x06,0x0c,0x05,0x81,0xd8,0x84,0x09,0xdc,0x0b,0x0f,0x0d,0x0e,0x10,0xdb,
611
0x11,0xca,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
612
{0xc4,0x02,0x03,0x04,0xcb,0x0a,0x07,0x08,0xd9,0x82,0xc8,0x83,0xc0,0xc1,0xda,0xc2,
613
0xc9,0xc3,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
616
{0x01,0x02,0x06,0x0a,0x83,0x0b,0x07,0x08,0x09,0x82,0xd8,0x0c,0xd9,0xda,0xff,0xff,
617
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
618
{0xc3,0x80,0x03,0x04,0x05,0x81,0xca,0xc8,0xdb,0xc9,0xc0,0xc1,0x0d,0xc2,0xff,0xff,
619
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
622
{0x01,0x02,0x03,0x04,0x81,0x07,0x08,0xd8,0xda,0xd9,0xff,0xff,0xff,0xff,0xff,0xff,
623
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
624
{0xc2,0x80,0x05,0xc9,0xc8,0x06,0x82,0xc0,0x09,0xc1,0xff,0xff,0xff,0xff,0xff,0xff,
625
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
628
{0x01,0x80,0x04,0xc8,0xc0,0xd9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
629
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
630
{0xc1,0x02,0x03,0x81,0x05,0xd8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
631
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
634
{0x01,0xd8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
635
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
636
{0xc0,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
637
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,},
641
UINT32 word_complete = 2;
646
switch(naomibd->prot.pak_state)
651
INT32 slot = (naomibd->prot.pak_buf_pos & (naomibd->prot.pak_buf_size-1));
654
if(slot < (naomibd->prot.pak_buf_size-7))
657
slot = (slot & 7) + 1;
660
if(naomibd_get_compressed_bit(naomibd))
661
tmp = trees[slot][1][tmp];
663
tmp = trees[slot][0][tmp];
666
naomibd->prot.pak_byte = (tmp&7)+1;
669
static INT32 cmds[4] = {0, 1, 0, -1};
670
naomibd->prot.pak_fetch_ofs = cmds[(tmp&0x18)>>3];
671
naomibd->prot.pak_state = CMD_FETCH;
676
naomibd->prot.pak_state = CMD_REPEAT;
677
byten = naomibd_get_compressed_bit(naomibd) << 1;
678
byten = (byten | naomibd_get_compressed_bit(naomibd)) << 1;
679
byten = (byten | naomibd_get_compressed_bit(naomibd)) << 1;
680
byten = (byten | naomibd_get_compressed_bit(naomibd)) << 1;
681
byten = (byten | naomibd_get_compressed_bit(naomibd)) << 1;
682
byten = (byten | naomibd_get_compressed_bit(naomibd)) << 1;
683
byten = (byten | naomibd_get_compressed_bit(naomibd)) << 1;
684
byten = byten | naomibd_get_compressed_bit(naomibd);
685
naomibd->prot.cmd_byte = byten;
691
naomibd->prot.cmd_byte = naomibd->prot.pak_buf[(naomibd->prot.pak_buf_pos-naomibd->prot.pak_buf_size+naomibd->prot.pak_fetch_ofs)&(PACK_BUF_SIZE-1)];
694
naomibd->prot.pak_buf[naomibd->prot.pak_buf_pos&(PACK_BUF_SIZE-1)]=naomibd->prot.cmd_byte;
697
wordn = naomibd->prot.cmd_byte << 8;
701
wordn = wordn | naomibd->prot.cmd_byte;
704
naomibd->prot.pak_byte--;
705
naomibd->prot.pak_buf_pos++;
706
if(naomibd->prot.pak_byte == 0) naomibd->prot.pak_state = CMD_READY;
713
// stream read protected PIO hook
714
//-----------------------------------------------------------
715
static UINT16 naomibd_get_data_stream(naomibd_state *naomibd)
719
if(naomibd->prot.control_bits&2)
721
wordn = naomibd_get_decompressed_stream(naomibd);
725
wordn = naomibd_get_decrypted_stream(naomibd);
731
void *naomibd_get_memory(device_t *device)
733
naomibd_state *naomibd = get_safe_token(device);
735
// for M1 decodes, return the buffer we'll DMA from
736
if (!(naomibd->dma_offset_flags & NAOMIBD_FLAG_DMA_COMPRESSION) && (naomibd->type == ROM_BOARD) && (naomibd->dc_dmakey != 0))
738
// perform the M1 decode
739
naomibd_m1_decode(naomibd);
741
// return the pointer to our output buffer
742
return naomibd->dc_cart_ram;
745
if (!(naomibd->dma_offset_flags & NAOMIBD_FLAG_DMA_COMPRESSION) && (naomibd->type == ROM_BOARD))
747
logerror("Unhandled M1 DMA with key %x, flags %x, offset %x\n", naomibd->dc_dmakey, naomibd->dma_offset_flags, naomibd->dma_offset);
750
return get_safe_token(device)->memory;
753
offs_t naomibd_get_dmaoffset(device_t *device)
755
naomibd_state *naomibd = get_safe_token(device);
758
#if NAOMIBD_PRINTF_PROTECTION
759
printf("DMA source %08x, flags %x\n", get_safe_token(device)->dma_offset, get_safe_token(device)->dma_offset_flags);
762
// if the flag is cleared that lets the protection chip go,
763
// we need to handle this specially. but not on DIMM boards or if there's no key.
764
if (!(naomibd->dma_offset_flags & NAOMIBD_FLAG_DMA_COMPRESSION) && (naomibd->type == ROM_BOARD) && (naomibd->dc_dmakey != 0))
766
// no offset, start at the beginning of cart ram for M1 transfers
771
result = get_safe_token(device)->dma_offset;
778
/*************************************
780
* Common initialization
782
*************************************/
786
static void naomibd_postload(naomibd_state *v)
791
static void init_save_state(device_t *device)
793
naomibd_state *v = get_safe_token(device);
795
device->machine().save().register_postload(save_prepost_delegate(FUNC(naomibd_postload), v));
797
/* register states */
798
device->save_item(NAME(v->rom_offset));
799
device->save_item(NAME(v->rom_offset_flags));
800
device->save_item(NAME(v->dma_count));
801
device->save_item(NAME(v->dma_offset));
802
device->save_item(NAME(v->dma_offset_flags));
803
device->save_item(NAME(v->prot_offset));
804
device->save_item(NAME(v->prot_key));
805
device->save_item(NAME(v->aw_offset));
806
device->save_item(NAME(v->aw_file_base));
807
device->save_item(NAME(v->aw_file_offset));
808
device->save_item(NAME(v->dc_m3_ptr));
809
device->save_item(NAME(v->dc_cart_ram));
810
device->save_item(NAME(v->prot.last_word));
811
device->save_item(NAME(v->prot.aux_word));
812
device->save_item(NAME(v->prot.pak_word));
813
device->save_item(NAME(v->prot.heading_word));
814
device->save_item(NAME(v->prot.count));
815
device->save_item(NAME(v->prot.pak_bit));
816
device->save_item(NAME(v->prot.control_bits));
817
device->save_item(NAME(v->prot.pak_state));
818
device->save_item(NAME(v->prot.dec_count));
819
device->save_item(NAME(v->prot.pak_buf_size));
820
device->save_item(NAME(v->prot.pak_buf_pos));
821
device->save_item(NAME(v->prot.pak_fetch_ofs));
822
device->save_item(NAME(v->prot.pak_byte));
823
device->save_item(NAME(v->prot.cmd_byte));
824
device->save_item(NAME(v->prot.seed));
825
device->save_item(NAME(v->prot.s_xor));
826
device->save_item(NAME(v->prot.s_dict));
827
device->save_item(NAME(v->prot.s_subst));
828
device->save_item(NAME(v->prot.s_out_len));
829
device->save_item(NAME(v->prot.s_out_cnt));
830
device->save_item(NAME(v->prot.s_shift));
831
device->save_item(NAME(v->prot.s_bits));
832
device->save_item(NAME(v->prot.s_in_len));
833
device->save_item(NAME(v->prot.s_in_pos));
838
/*************************************
842
*************************************/
844
static void soft_reset(naomibd_state *v)
852
/*************************************
856
*************************************/
858
READ64_DEVICE_HANDLER( naomibd_r )
860
naomibd_state *v = get_safe_token(device);
861
UINT8 *ROM = (UINT8 *)v->memory;
863
// AW board is different, shouldn't ever be read
864
if (v->type == AW_ROM_BOARD)
866
mame_printf_debug("AW_ROM_BOARD read @ %x mask %" I64FMT "x\n", offset, mem_mask);
867
return U64(0xffffffffffffffff);
871
if ((offset == 1) && ACCESSING_BITS_0_15)
875
if (v->rom_offset_flags & NAOMIBD_FLAG_SPECIAL_MODE)
877
// can we live-decrypt this game?
878
if (v->dc_gamekey != -1)
880
ret = (UINT64)naomibd_get_data_stream(v);
889
ret = (UINT64)(ROM[v->rom_offset] | (ROM[v->rom_offset+1]<<8));
892
if (v->rom_offset_flags & NAOMIBD_FLAG_AUTO_ADVANCE)
899
else if ((offset == 2) && ACCESSING_BITS_32_63)
901
// Actel FPGA ID, used on some games for a "special" ROM test.
903
// without this (by returning 0xffff) some games will do a rom test where
904
// the IC numbers tested do not relate to the actual ROMs on the cart,
905
// and a fake 'IC1' will be tested, which returns mirrored data from the
906
// other roms in order to pass if enabled on the real hardware.
907
// (certain bios / board combinations will also cause this, so it is
908
// important that we mirror the data in the rom loading using ROM_COPY)
910
//return (UINT64)0xffff << 32;
911
return (UINT64)actel_id << 32;
913
else if ((offset == 7) && ACCESSING_BITS_32_47)
916
mame_printf_verbose("ROM: read 5f703c\n");
917
return (UINT64)0xffff << 32;
919
else if ((offset == 8) && ACCESSING_BITS_0_15)
922
mame_printf_verbose("ROM: read 5f7040\n");
925
else if ((offset == 8) && ACCESSING_BITS_32_47)
928
mame_printf_verbose("ROM: read 5f7044\n");
931
else if ((offset == 9) && ACCESSING_BITS_0_15)
934
mame_printf_verbose("ROM: read 5f7048\n");
937
else if ((offset == 9) && ACCESSING_BITS_32_47)
940
mame_printf_verbose("ROM: read 5f704c\n");
941
return (UINT64)1 << 32;
943
else if ((offset == 15) && ACCESSING_BITS_32_47) // boardid read
947
ret = device->machine().device<x76f100_device>("naomibd_eeprom")->sda_r() << 15;
953
//mame_printf_verbose("%s:ROM: read mask %" I64FMT "x @ %x\n", machine.describe_context(), mem_mask, offset);
956
return U64(0xffffffffffffffff);
959
WRITE64_DEVICE_HANDLER( naomibd_w )
961
naomibd_state *v = get_safe_token(device);
964
if (v->type == AW_ROM_BOARD)
966
//printf("AW: %" I64FMT "x to ROM board @ %x (mask %" I64FMT "x)\n", data, offset, mem_mask);
972
if(ACCESSING_BITS_0_15)
975
v->aw_offset &= 0xffff0000;
976
v->aw_offset |= (data & 0xffff);
977
v->dma_offset = v->aw_offset*2;
978
//printf("EPR_OFFSETL = %x, dma_offset %x\n", (UINT32)data, v->dma_offset);
980
else if(ACCESSING_BITS_32_47 || ACCESSING_BITS_32_63)
983
v->aw_offset &= 0xffff;
984
v->aw_offset |= ((data>>16) & 0xffff0000);
985
v->dma_offset = v->aw_offset*2;
986
v->dma_offset_flags = NAOMIBD_FLAG_DMA_COMPRESSION|NAOMIBD_FLAG_AUTO_ADVANCE; // force normal DMA mode
987
//printf("EPR_OFFSETH = %x, dma_offset %x\n", (UINT32)(data>>32), v->dma_offset);
995
if(ACCESSING_BITS_32_47 || ACCESSING_BITS_32_63)
998
//printf("%x to RECORD_INDEX\n", (UINT32)(data>>32));
999
v->dma_offset = 0x1000000 + (0x40 * (data>>32));
1006
if(ACCESSING_BITS_0_15)
1008
UINT8 *ROM = (UINT8 *)v->memory;
1011
// MPR_FIRST_FILE_INDEX (usually 3)
1013
v->aw_file_base = ROM[0x100000b+base]<<24 | ROM[0x100000a+base]<<16 | ROM[0x1000009+base]<<8 | ROM[0x1000008+base];
1014
v->aw_file_base += 0x1000000;
1015
//printf("%x to FIRST_FILE_INDEX, file_base = %x\n", (UINT32)data, v->aw_file_base);
1017
else if(ACCESSING_BITS_32_47 || ACCESSING_BITS_32_63)
1020
v->aw_file_offset &= 0xffff0000;
1021
v->aw_file_offset |= (data>>32) & 0xffff;
1022
v->dma_offset = v->aw_file_base + (v->aw_file_offset*2);
1023
//printf("%x to FILE_OFFSETL, file_offset %x, dma_offset %x\n", (UINT32)(data>>32), v->aw_file_offset, v->dma_offset);
1030
if(ACCESSING_BITS_0_15)
1033
v->aw_file_offset &= 0xffff;
1034
v->aw_file_offset |= (data & 0xffff)<<16;
1035
v->dma_offset = v->aw_file_base + (v->aw_file_offset*2);
1036
//printf("%x to FILE_OFFSETH, file_offset %x, dma_offset %x\n", (UINT32)data, v->aw_file_offset, v->dma_offset);
1042
logerror("AW: unhandled %" I64FMT "x to ROM board @ %x (mask %" I64FMT "x)\n", data, offset, mem_mask);
54
DEVICE_ADDRESS_MAP_START(submap, 16, naomi_board)
55
AM_RANGE(0x00, 0x01) AM_WRITE(rom_offseth_w)
56
AM_RANGE(0x02, 0x03) AM_WRITE(rom_offsetl_w)
57
AM_RANGE(0x04, 0x05) AM_READWRITE(rom_data_r, rom_data_w)
58
AM_RANGE(0x06, 0x07) AM_WRITE(dma_offseth_w)
59
AM_RANGE(0x08, 0x09) AM_WRITE(dma_offsetl_w)
60
AM_RANGE(0x0a, 0x0b) AM_WRITE(dma_count_w)
61
AM_RANGE(0x3c, 0x3d) AM_WRITE(boardid_w)
62
AM_RANGE(0x3e, 0x3f) AM_READ(boardid_r)
64
AM_RANGE(0x00, 0xff) AM_READ(default_r)
67
naomi_board::naomi_board(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock)
68
: naomi_g1_device(mconfig, type, name, tag, owner, clock)
73
void naomi_board::static_set_eeprom_tag(device_t &device, const char *_eeprom_tag)
75
naomi_board &dev = downcast<naomi_board &>(device);
76
dev.eeprom_tag = _eeprom_tag;
80
void naomi_board::device_start()
82
naomi_g1_device::device_start();
84
save_item(NAME(rom_offset));
85
save_item(NAME(dma_offset));
86
save_item(NAME(dma_count));
87
save_item(NAME(dma_cur_offset));
88
save_item(NAME(pio_ready));
89
save_item(NAME(dma_ready));
92
eeprom = machine().device<x76f100_device>(eeprom_tag);
97
void naomi_board::device_reset()
99
naomi_g1_device::device_reset();
107
void naomi_board::dma_get_position(UINT8 *&base, UINT32 &limit, bool to_mainram)
1053
if(ACCESSING_BITS_0_15)
1056
v->rom_offset &= 0xffff;
1057
v->rom_offset |= (data & 0x1fff)<<16;
1058
v->rom_offset_flags = data >> 12;
1060
if(ACCESSING_BITS_32_47)
1063
v->rom_offset &= 0xffff0000;
1064
v->rom_offset |= ((data >> 32) & 0xffff);
1067
#if NAOMIBD_PRINTF_PROTECTION
1068
printf("PIO: offset to %x\n", v->rom_offset);
1074
if(ACCESSING_BITS_32_47 || ACCESSING_BITS_32_63)
1077
v->dma_offset &= 0xffff;
1078
v->dma_offset |= (data >> 16) & 0x1fff0000;
1079
v->dma_offset_flags = (data>>(28+16));
1081
if(ACCESSING_BITS_0_15)
1083
// ROM_DATA - used to access registers in the protection chip
1084
switch (v->rom_offset)
1086
case 0x1fff8: // offset low
1087
v->prot_offset &= 0xffff0000;
1088
v->prot_offset |= (UINT32)data;
1091
case 0x1fffa: // offset high
1092
v->prot_offset &= 0xffff;
1093
v->prot_offset |= (UINT32)data<<16;
1096
case 0x1fffc: // decryption key
1099
#if NAOMIBD_PRINTF_PROTECTION
1100
printf("Protection: set up read @ %x, key %x (PIO %x DMA %x) [%s]\n", v->prot_offset*2, v->prot_key, v->rom_offset, v->dma_offset, device->machine().describe_context());
1103
// if dc_gamekey isn't -1, we can live-decrypt this one
1104
if (v->dc_gamekey != -1)
1106
UINT8 *ROM = (UINT8 *)v->memory;
1108
v->dc_seqkey = v->prot_key;
1110
if (v->prot_offset != 0x2000000/2)
1112
// M2: decrypt from ROM
1113
v->prot.ptr = (UINT16 *)&ROM[v->prot_offset*2];
1114
v->prot.seed = v->prot_offset&0xffff;
1115
#if NAOMIBD_PRINTF_PROTECTION
1116
printf("M2 decrypt: gamekey %x seqkey %x length %x\n", v->dc_gamekey, v->dc_seqkey, v->dc_m3_ptr);
1121
// M3: decrypt from cart ram
1122
v->prot.ptr = (UINT16 *)v->dc_cart_ram;
1124
#if NAOMIBD_PRINTF_PROTECTION
1125
printf("M3 decrypt: gamekey %x seqkey %x length %x\n", v->dc_gamekey, v->dc_seqkey, v->dc_m3_ptr);
1130
naomibd_init_stream(v);
1134
#if NAOMIBD_PRINTF_PROTECTION
1137
printf("naomibd: protection not handled for this game\n");
1144
v->dc_cart_ram[v->dc_m3_ptr] = (data&0xff);
1145
v->dc_cart_ram[v->dc_m3_ptr+1] = (data>>8)&0xff;
1150
#if NAOMIBD_PRINTF_PROTECTION
1151
printf("naomibd: unknown protection write %x @ %x\n", (UINT32)data, v->rom_offset);
1160
if(ACCESSING_BITS_0_15)
1163
v->dma_offset &= 0xffff0000;
1164
v->dma_offset |= (data & 0xffff);
1166
if(ACCESSING_BITS_32_63)
1169
v->dma_count = data >> 32;
1175
if(ACCESSING_BITS_32_47)
1176
mame_printf_verbose("ROM: write 5f703c\n");
1181
if(ACCESSING_BITS_0_15)
1182
mame_printf_verbose("ROM: write 5f7040\n");
1183
if(ACCESSING_BITS_32_47)
1184
mame_printf_verbose("ROM: write 5f7044\n");
1189
if(ACCESSING_BITS_0_15)
1190
mame_printf_verbose("ROM: write 5f7048\n");
1191
if(ACCESSING_BITS_32_47)
1192
mame_printf_verbose("ROM: write 5f704c\n");
1197
if(ACCESSING_BITS_0_15)
1199
x76f100_device *x76f100 = device->machine().device<x76f100_device>("naomibd_eeprom");
1200
// NAOMI_BOARDID_WRITE
1201
x76f100->cs_w((data >> 2) & 1);
1202
x76f100->rst_w((data >> 3) & 1);
1203
x76f100->scl_w((data >> 1) & 1);
1204
x76f100->sda_w((data >> 0) & 1);
1209
mame_printf_verbose("%s: ROM: write %" I64FMT "x to %x, mask %" I64FMT "x\n", device->machine().describe_context(), data, offset, mem_mask);
1216
/*************************************
1218
* Load rom file from gdrom
1220
*************************************/
1222
#define FILENAME_LENGTH 24
1224
static void load_rom_gdrom(running_machine& machine, naomibd_state *v)
1227
cdrom_file *gdromfile;
1230
UINT32 start,size,sectors,dir;
1234
UINT8* realpic; // todo, add to device
1236
memset(name,'\0',128);
1238
realpic = machine.region("pic")->base();
1242
//printf("Real PIC binary found\n");
1246
name[i] = realpic[0x7c0+i*2];
1250
name[i+7] = realpic[0x7e0+i*2];
1255
// use extracted pic data
1256
logerror("This PIC key hasn't been converted to a proper PIC binary yet!\n");
1257
memcpy(name, v->picdata+33, 7);
1258
memcpy(name+7, v->picdata+25, 7);
1261
gdromfile = cdrom_open(v->gdromchd);
1262
// primary volume descriptor
1263
// read frame 0xb06e (frame=sector+150)
1264
// dimm board firmware starts straight from this frame
1265
cdrom_read_data(gdromfile, 0xb06e - 150, buffer, CD_TRACK_MODE1);
1266
start=((buffer[0x8c+0] << 0) |
1267
(buffer[0x8c+1] << 8) |
1268
(buffer[0x8c+2] << 16) |
1269
(buffer[0x8c+3] << 24));
1271
cdrom_read_data(gdromfile, start, buffer, CD_TRACK_MODE1);
1272
start=((buffer[0x2+0] << 0) |
1273
(buffer[0x2+1] << 8) |
1274
(buffer[0x2+2] << 16) |
1275
(buffer[0x2+3] << 24));
1278
cdrom_read_data(gdromfile, dir, buffer, CD_TRACK_MODE1);
1279
// find data of file
1282
logerror("Looking for file %s\n", name);
1283
for (pos = 0;pos < 2048;pos += buffer[pos])
1286
if (!(buffer[pos+25] & 2))
1289
for (a=0;a < FILENAME_LENGTH;a++)
1291
if ((buffer[pos+33+a] == ';') && (name[a] == 0))
1293
a=FILENAME_LENGTH+1;
1296
if (buffer[pos+33+a] != name[a])
1301
a = FILENAME_LENGTH+1;
1303
a = FILENAME_LENGTH;
1307
if (a == FILENAME_LENGTH+1)
1309
// start sector and size of file
1310
start=((buffer[pos+2] << 0) |
1311
(buffer[pos+3] << 8) |
1312
(buffer[pos+4] << 16) |
1313
(buffer[pos+5] << 24));
1314
size =((buffer[pos+10] << 0) |
1315
(buffer[pos+11] << 8) |
1316
(buffer[pos+12] << 16) |
1317
(buffer[pos+13] << 24));
1319
logerror("start %08x size %08x\n", start,size);
1322
if (buffer[pos] == 0)
1326
if ((start != 0) && (size == 0x100))
1329
cdrom_read_data(gdromfile, start, buffer, CD_TRACK_MODE1);
1330
// get "rom" file name
1331
memset(name,'\0', 128);
1332
memcpy(name, buffer+0xc0, FILENAME_LENGTH-1);
1336
cdrom_read_data(gdromfile, dir, buffer, CD_TRACK_MODE1);
1337
// find data of "rom" file
1341
logerror("Looking for file %s\n", name);
1342
for (pos = 0;pos < 2048;pos += buffer[pos])
1345
if (!(buffer[pos+25] & 2))
1347
len = buffer[pos+32];
1348
for (a=0;a < FILENAME_LENGTH;a++)
1350
if ((buffer[pos+33+a] == ';') && (name[a] == 0))
1352
a=FILENAME_LENGTH+1;
1355
if (buffer[pos+33+a] != name[a])
1360
a = (FILENAME_LENGTH+1);
1362
a = FILENAME_LENGTH;
1366
if (a == (FILENAME_LENGTH+1))
1368
// start sector and size of file
1369
start=((buffer[pos+2] << 0) |
1370
(buffer[pos+3] << 8) |
1371
(buffer[pos+4] << 16) |
1372
(buffer[pos+5] << 24));
1373
size =((buffer[pos+10] << 0) |
1374
(buffer[pos+11] << 8) |
1375
(buffer[pos+12] << 16) |
1376
(buffer[pos+13] << 24));
1378
logerror("start %08x size %08x\n", start,size);
1381
if (buffer[pos] == 0)
1386
// read encrypted data into memory
1388
sectors = (size+2047)/2048;
1391
cdrom_read_data(gdromfile, start, ptr, CD_TRACK_MODE1);
1399
realpic = machine.region("pic")->base();
1407
key |= (UINT64)realpic[0x780+i*2] << (56 - i*8);
1410
key |= (UINT64)realpic[0x7a0];
1414
key =(((UINT64)v->picdata[0x31] << 56) |
1415
((UINT64)v->picdata[0x32] << 48) |
1416
((UINT64)v->picdata[0x33] << 40) |
1417
((UINT64)v->picdata[0x34] << 32) |
1418
((UINT64)v->picdata[0x35] << 24) |
1419
((UINT64)v->picdata[0x36] << 16) |
1420
((UINT64)v->picdata[0x37] << 8) |
1421
((UINT64)v->picdata[0x29] << 0));
1424
logerror("key is %08x%08x\n", (UINT32)((key & 0xffffffff00000000ULL)>>32), (UINT32)(key & 0x00000000ffffffffULL));
1426
// decrypt loaded data
1427
naomi_game_decrypt(machine, key, v->memory, size);
1428
cdrom_close(gdromfile);
1431
/***************************************************************************
1432
DECRYPTION EMULATION
1434
By convention, we label the three known cart protection methods this way (using Deunan Knute's wording):
1435
M1: DMA read of protected ROM area
1436
M2: special read of ROM area which supplies decryption key first
1437
M3: normal read followed by write to cart's decryption buffer (up to 64kB), followed by M2 but from buffer area
1439
Notes below refer to M2 & M3.
1441
The encryption is done by a stream cipher operating in counter mode, which use a 16-bits internal block cipher.
1443
There are 2 "control bits" at the start of the decrypted stream which control the mode of operation: bit #1 set to 1 means
1444
that the decrypted stream needs to be decompressed after being decrypted. More on this later.
1446
The next 16-bits are part of the header (they don't belong to the plaintext), but his meaning is unclear. It has been
1447
conjectured that it could stablish when to "reset" the process and start processing a new stream (based on some tests
1448
on WWFROYAL, in which the decryption's output doesn't seem to be valid for more than some dozens of words), but some
1449
more testing would be needed for clarifying that.
1451
After those 18 heading bits, we find the proper plaintext. It must be noted that, due to the initial 2 special bits,
1452
the 16-bits words of the plaintext are shifted 2 bits respect to the word-boundaries of the output stream of the
1453
internal block-cipher. So, at a given step, the internal block cipher will output 16-bits, 14 of which will go to a
1454
given plaintext word, and the remaining 2 to the next plaintext word.
1456
The underlying block cipher consists of two 4-round Feistel Networks (FN): the first one takes the counter (16 bits),
1457
the game-key (>=26 bits) and the sequence-key (16 bits) and output a middle result (16 bits) which will act as another key
1458
for the second one. The second FN will take the encrypted word (16 bits), the game-key, the sequence-key and the result
1459
from the first FN and will output the decrypted word (16 bits).
1461
Each round of the Feistel Networks use four substitution sboxes, each having 6 inputs and 2 outputs. The input can be the
1462
XOR of at most two "sources bits", being source bits the bits from the previous round and the bits from the different keys.
1464
The underlying block cipher has the same structure than the one used by the CPS-2 (Capcom Play System 2) and,
1465
indeed, some of the used sboxes are exactly the same and appear in the same FN/round in both systems (this is not evident,
1466
as you need to apply a bitswapping and some XORs to the input & output of the sboxes to get the same values due). However,
1467
the key scheduling used by this implementation is much weaker than the CPS-2's one. Many s-boxes inputs are XORed with any
1470
Due to the small key-length, no sophisticated attacks are needed to recover the keys; a brute-force attack knowing just
1471
some (encrypted word-decrypted word) pairs suffice. However, due to the weak key scheduling, it should be noted that some
1472
related keys can produce the same output bytes for some (short) input sequences.
1474
The only difference in the decryption process between M2 and M3 is the initialization of the counter. In M3, the counter is
1475
always set to 0 at the beginning of the decryption while, in M2, the bits #1-#16 of the ciphertext's address are used
1476
to initialize the counter.
1478
Due to the nature of the cipher, there are some degrees of freedom when choosing the s-boxes and keys values; by example,
1479
you could apply a fixed bitswapping and XOR to the keys and the decryption would remain the same as long as you change
1480
accordingly the s-boxes' definitions. So the order of the bits in the keys is arbitrary, and the s-boxes values have been
1481
chosen so as to make the key for CAPSNK equal to 0.
1483
It can be observed that a couple of sboxes have incomplete tables (a 255 value indicate an unknown value). The recovered keys
1484
as of december/2010 show small randomness and big correlations, making possible that some unseen bits could make the
1485
decryption need those incomplete parts.
1487
****************************************************************************************/
1492
int inputs[6]; // positions of the inputs bits, -1 means no input except from key
1493
int outputs[2]; // positions of the output bits
1497
static const struct sbox fn1_sboxes[4][4] =
1502
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,
1503
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,
1511
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,
1512
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,
1520
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,
1521
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,
1529
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,
1530
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,
1539
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,
1540
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,
1548
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,
1549
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,
1557
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,
1558
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,
1566
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,
1567
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,
1576
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,
1577
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,
1585
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,
1586
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,
1594
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,
1596
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,
1604
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,
1605
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,
1614
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,
1615
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,
1623
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,
1624
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,
1632
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,
1633
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,
1641
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,
1642
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,
1651
static const struct sbox fn2_sboxes[4][4] =
1656
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,
1657
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,
1665
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,
1666
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,
1674
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,
1675
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,
1683
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,
1684
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,
1693
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,
1694
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,
1702
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,
1703
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,
1711
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,
1712
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,
1720
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,
1721
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,
1730
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,
1731
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,
1739
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,
1740
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,
1748
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,
1750
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,
1758
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,
1759
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,
1768
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,
1769
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,
1777
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,
1778
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,
1786
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,
1787
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,
1795
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,
1796
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,
1804
static const int fn1_game_key_scheduling[38][2] =
1806
{1,29}, {1,71}, {2,4}, {2,54}, {3,8}, {4,56}, {4,73}, {5,11},
1807
{6,51}, {7,92}, {8,89}, {9,9}, {9,10}, {9,39}, {9,41}, {9,58},
1808
{9,59}, {9,86}, {10,90}, {11,6}, {12,64}, {13,49}, {14,44}, {15,40},
1809
{16,69}, {17,15}, {18,23}, {18,43}, {19,82}, {20,81}, {21,32}, {21,61},
1810
{22,5}, {23,66}, {24,13}, {24,45}, {25,12}, {25,35}
1813
static const int fn2_game_key_scheduling[34][2] =
1815
{0,0}, {1,3}, {2,11}, {3,20}, {4,22}, {5,23}, {6,29}, {7,38},
1816
{8,39}, {9,47}, {9,55}, {9,86}, {9,87}, {9,90}, {10,50}, {10,53},
1817
{11,57}, {12,59}, {13,61}, {13,64}, {14,63}, {15,67}, {16,72}, {17,83},
1818
{18,88}, {19,94}, {20,35}, {21,17}, {21,92}, {22,6}, {22,11}, {23,85},
1822
static const int fn1_sequence_key_scheduling[20][2] =
1824
{0,52}, {1,34}, {2,17}, {3,36}, {4,84}, {4,88}, {5,57}, {6,48},
1825
{6,68}, {7,76}, {8,83}, {9,30}, {10,22}, {10,41}, {11,38}, {12,55},
1826
{13,74}, {14,19}, {14,80}, {15,26}
1829
static const int fn2_sequence_key_scheduling[16] = {77,34,8,42,36,27,69,66,13,9,79,31,49,7,24,64};
1831
static const int fn2_middle_result_scheduling[16] = {1,10,44,68,74,78,81,95,2,4,30,40,41,51,53,58};
1833
static int feistel_function(int input, const struct sbox* sboxes, UINT32 subkeys)
1839
for (m=0; m<4; ++m) // 4 sboxes
1841
for (k=0, aux=0; k<6; ++k)
1843
if (sboxes[m].inputs[k]!=-1)
1845
aux |= (BIT(input, sboxes[m].inputs[k])<<k);
1849
aux = sboxes[m].table[(aux^subkeys)&0x3f];
1853
result |= (BIT(aux,k)<<sboxes[m].outputs[k]);
1862
/**************************
1863
This implementation is an "educational" version. It must be noted that it can be speed-optimized in a number of ways.
1864
The most evident one is to factor out the parts of the key-scheduling that must only be done once (like the game-key &
1865
sequence-key parts) as noted in the comments inlined in the function. More sophisticated speed-ups can be gained by
1866
noticing that the weak key-scheduling would allow to create some pregenerated look-up tables for doing most of the work
1867
of the function. Even so, it would still be pretty slow, so caching techniques could be a wiser option here.
1868
**************************/
1870
static UINT16 block_decrypt(UINT32 game_key, UINT16 sequence_key, UINT16 counter, UINT16 data)
1876
UINT32 fn1_subkeys[4];
1877
UINT32 fn2_subkeys[4];
1879
/* Game-key scheduling; this could be done just once per game at initialization time */
1880
memset(fn1_subkeys,0,sizeof(UINT32)*4);
1881
memset(fn2_subkeys,0,sizeof(UINT32)*4);
1883
for (j=0; j<38; ++j)
1885
if (BIT(game_key, fn1_game_key_scheduling[j][0])!=0)
1887
aux = fn1_game_key_scheduling[j][1]%24;
1888
aux2 = fn1_game_key_scheduling[j][1]/24;
1889
fn1_subkeys[aux2] ^= (1<<aux);
1893
for (j=0; j<34; ++j)
1895
if (BIT(game_key, fn2_game_key_scheduling[j][0])!=0)
1897
aux = fn2_game_key_scheduling[j][1]%24;
1898
aux2 = fn2_game_key_scheduling[j][1]/24;
1899
fn2_subkeys[aux2] ^= (1<<aux);
1902
/********************************************************/
1904
/* Sequence-key scheduling; this could be done just once per decryption run */
1905
for (j=0; j<20; ++j)
1907
if (BIT(sequence_key,fn1_sequence_key_scheduling[j][0])!=0)
1909
aux = fn1_sequence_key_scheduling[j][1]%24;
1910
aux2 = fn1_sequence_key_scheduling[j][1]/24;
1911
fn1_subkeys[aux2] ^= (1<<aux);
1915
for (j=0; j<16; ++j)
1917
if (BIT(sequence_key,j)!=0)
1919
aux = fn2_sequence_key_scheduling[j]%24;
1920
aux2 = fn2_sequence_key_scheduling[j]/24;
1921
fn2_subkeys[aux2] ^= (1<<aux);
1925
// subkeys bits 10 & 41
1926
fn2_subkeys[0] ^= (BIT(sequence_key,2)<<10);
1927
fn2_subkeys[1] ^= (BIT(sequence_key,4)<<17);
1928
/**************************************************************/
1930
// First Feistel Network
1932
aux = BITSWAP16(counter,5,12,14,13,9,3,6,4, 8,1,15,11,0,7,10,2);
1936
A = (aux & 0xff) ^ feistel_function(B,fn1_sboxes[0],fn1_subkeys[0]);
1939
B = B ^ feistel_function(A,fn1_sboxes[1],fn1_subkeys[1]);
1942
A = A ^ feistel_function(B,fn1_sboxes[2],fn1_subkeys[2]);
1945
B = B ^ feistel_function(A,fn1_sboxes[3],fn1_subkeys[3]);
1947
middle_result = (B<<8)|A;
1950
/* Middle-result-key sheduling */
1951
for (j=0; j<16; ++j)
1953
if (BIT(middle_result,j)!=0)
1955
aux = fn2_middle_result_scheduling[j]%24;
1956
aux2 = fn2_middle_result_scheduling[j]/24;
1957
fn2_subkeys[aux2] ^= (1<<aux);
1960
/*********************/
1962
// Second Feistel Network
1964
aux = BITSWAP16(data,14,3,8,12,13,7,15,4, 6,2,9,5,11,0,1,10);
1968
A = (aux & 0xff) ^ feistel_function(B,fn2_sboxes[0],fn2_subkeys[0]);
1971
B = B ^ feistel_function(A,fn2_sboxes[1],fn2_subkeys[1]);
1974
A = A ^ feistel_function(B,fn2_sboxes[2],fn2_subkeys[2]);
1977
B = B ^ feistel_function(A,fn2_sboxes[3],fn2_subkeys[3]);
1981
aux = BITSWAP16(aux,15,7,6,14,13,12,5,4, 3,2,11,10,9,1,0,8);
1986
/***************************************************************************
1988
***************************************************************************/
1990
/*-------------------------------------------------
1991
device start callback
1992
-------------------------------------------------*/
1994
static DEVICE_START( naomibd )
1996
const naomibd_config *config = (const naomibd_config *)downcast<const legacy_device_base *>(device)->inline_config();
1997
naomibd_state *v = get_safe_token(device);
2000
/* validate some basic stuff */
2001
assert(device->static_config() == NULL);
2002
assert(downcast<const legacy_device_base *>(device)->inline_config() != NULL);
2004
/* validate configuration */
2005
assert(config->type >= ROM_BOARD && config->type < MAX_NAOMIBD_TYPES);
2007
/* store a pointer back to the device */
2012
for (i=0; i<ARRAY_LENGTH(naomibd_translate_tbl); i++)
2014
if (!strcmp(device->machine().system().name, naomibd_translate_tbl[i].name))
2016
v->dc_gamekey = naomibd_translate_tbl[i].m2m3_key;
2017
v->dc_dmakey = naomibd_translate_tbl[i].m1_key;
2022
/* configure type-specific values */
2023
switch (config->type)
2026
v->memory = (UINT8 *)device->machine().region(config->regiontag)->base();
2030
v->memory = (UINT8 *)device->machine().region(config->regiontag)->base();
2034
v->memory = (UINT8 *)auto_alloc_array_clear(device->machine(), UINT8, 0x40000000); // 0x40000000 is needed for some Chihiro sets, Naomi should be less, we should pass as device param
2035
v->gdromchd = get_disk_handle(device->machine(), config->gdromregiontag);
2036
v->picdata = (UINT8 *)device->machine().region(config->picregiontag)->base();
2037
if (v->memory != NULL && v->gdromchd != NULL && v->picdata != NULL)
2038
load_rom_gdrom(device->machine(), v);
2042
fatalerror("Unsupported plug-in board in naomibd_start!");
2047
v->index = device->machine().devicelist().indexof(device->type(), device->tag());
2048
v->type = config->type;
2050
/* initialize some registers */
2052
v->rom_offset_flags = 0;
2055
v->dma_offset_flags = 0;
2058
/* do a soft reset to reset everything else */
2061
/* register for save states */
2062
init_save_state(device);
2066
/*-------------------------------------------------
2067
device exit callback
2068
-------------------------------------------------*/
2070
static DEVICE_STOP( naomibd )
2072
//naomibd_state *v = get_safe_token(device);
2076
/*-------------------------------------------------
2077
device reset callback
2078
-------------------------------------------------*/
2080
static DEVICE_RESET( naomibd )
2082
naomibd_state *v = get_safe_token(device);
2087
/*-------------------------------------------------
2088
device get info callback
2089
-------------------------------------------------*/
2091
DEVICE_GET_INFO( naomibd )
2093
const naomibd_config *config = (device != NULL) ? (const naomibd_config *)downcast<const legacy_device_base *>(device)->inline_config() : NULL;
2096
/* --- the following bits of info are returned as 64-bit signed integers --- */
2097
case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(naomibd_state); break;
2098
case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = sizeof(naomibd_config); break;
2100
/* --- the following bits of info are returned as pointers --- */
2101
case DEVINFO_PTR_ROM_REGION: info->romregion = NULL; break;
2102
case DEVINFO_PTR_MACHINE_CONFIG: info->machine_config = NULL; break;
2104
/* --- the following bits of info are returned as pointers to data or functions --- */
2105
case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(naomibd); break;
2106
case DEVINFO_FCT_STOP: info->stop = DEVICE_STOP_NAME(naomibd); break;
2107
case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(naomibd); break;
2109
/* --- the following bits of info are returned as NULL-terminated strings --- */
2110
case DEVINFO_STR_NAME:
2111
switch (config->type)
2114
case ROM_BOARD: strcpy(info->s, "Naomi Rom Board"); break;
2115
case AW_ROM_BOARD: strcpy(info->s, "Atomiswave Rom Board"); break;
2116
case DIMM_BOARD: strcpy(info->s, "Naomi Dimm Board"); break;
2119
case DEVINFO_STR_FAMILY: strcpy(info->s, "Naomi/Atomiswave plug-in board"); break;
2120
case DEVINFO_STR_VERSION: strcpy(info->s, "1.1"); break;
2121
case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
2122
case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright Nicola Salmoria and the MAME Team"); break;
2127
DEFINE_LEGACY_DEVICE(NAOMI_BOARD, naomibd);
116
if(!(dma_offset & 0x80000000))
117
throw emu_fatalerror("NAOMI BOARD: Unsupported, non-incrementing DMA.\n");
118
board_setup_address(dma_offset, true);
123
board_get_buffer(base, limit);
124
UINT32 blimit = 0x20*dma_count - dma_cur_offset;
125
if(0 && limit > blimit)
129
void naomi_board::dma_advance(UINT32 size)
131
dma_cur_offset += size;
135
WRITE16_MEMBER(naomi_board::rom_offseth_w)
137
rom_offset = (rom_offset & 0x0000ffff) | (data << 16);
141
WRITE16_MEMBER(naomi_board::rom_offsetl_w)
143
rom_offset = (rom_offset & 0xffff0000) | data;
147
READ16_MEMBER(naomi_board::rom_data_r)
150
board_setup_address(rom_offset, false);
157
board_get_buffer(buffer, size);
159
res = buffer[0] | (buffer[1] << 8);
160
if(rom_offset & 0x80000000)
165
WRITE16_MEMBER(naomi_board::rom_data_w)
167
board_write(rom_offset, data);
169
if(rom_offset & 0x80000000)
173
WRITE16_MEMBER(naomi_board::dma_offseth_w)
175
dma_offset = (dma_offset & 0x0000ffff) | (data << 16);
179
WRITE16_MEMBER(naomi_board::dma_offsetl_w)
181
dma_offset = (dma_offset & 0xffff0000) | data;
185
WRITE16_MEMBER(naomi_board::dma_count_w)
190
WRITE16_MEMBER(naomi_board::boardid_w)
192
eeprom->cs_w((data >> 2) & 1);
193
eeprom->rst_w((data >> 3) & 1);
194
eeprom->scl_w((data >> 1) & 1);
195
eeprom->sda_w((data >> 0) & 1);
198
READ16_MEMBER(naomi_board::boardid_r)
200
return eeprom->sda_r() << 15;
203
READ16_MEMBER(naomi_board::default_r)
205
logerror("NAOMIBD: unmapped read at %02x\n", offset);
209
void naomi_board::board_write(offs_t offset, UINT16 data)
211
logerror("NAOMIBD: unhandled board write %08x, %04x\n", offset, data);