Previous 199869 Revisions Next

r21590 Tuesday 5th March, 2013 at 11:01:22 UTC by Fabio Priuli
moved snes add-on chips emulation to src/mess/, at last.
[src/mame]mame.mak
[src/mame/includes]snes.h
[src/mame/machine]cx4data.c cx4fn.c cx4oam.c cx4ops.c snes.c snes7110.c snescx4.c snescx4.h snesobc1.c snesrtc.c snessdd1.c
[src/mess]mess.mak
[src/mess/machine]cx4data.c* cx4fn.c* cx4oam.c* cx4ops.c* snes7110.c* snescart.c snescart.h snescx4.c* snescx4.h* snesobc1.c* snesrtc.c* snessdd1.c*

trunk/src/mess/mess.mak
r21589r21590
21372137# miscellaneous dependencies
21382138#-------------------------------------------------
21392139
2140$(MAME_MACHINE)/snes.o: $(MAMESRC)/machine/snesobc1.c \
2141            $(MAMESRC)/machine/snescx4.c \
2142            $(MAMESRC)/machine/cx4ops.c \
2143            $(MAMESRC)/machine/cx4oam.c \
2144            $(MAMESRC)/machine/cx4fn.c \
2145            $(MAMESRC)/machine/cx4data.c \
2146            $(MAMESRC)/machine/snesrtc.c \
2147            $(MAMESRC)/machine/snessdd1.c \
2148            $(MAMESRC)/machine/snes7110.c \
2140$(MESS_MACHINE)/snescart.o: $(MESSSRC)/machine/snesobc1.c \
2141            $(MESSSRC)/machine/snescx4.c \
2142            $(MESSSRC)/machine/cx4ops.c \
2143            $(MESSSRC)/machine/cx4oam.c \
2144            $(MESSSRC)/machine/cx4fn.c \
2145            $(MESSSRC)/machine/cx4data.c \
2146            $(MESSSRC)/machine/snesrtc.c \
2147            $(MESSSRC)/machine/snessdd1.c \
2148            $(MESSSRC)/machine/snes7110.c \
21492149
21502150$(MESS_VIDEO)/gba.o:        $(MESSSRC)/video/gbamode0.c \
21512151            $(MESSSRC)/video/gbamode1.c \
trunk/src/mess/machine/snessdd1.c
r0r21590
1/***************************************************************************
2
3  snessdd1.c
4
5  File to handle emulation of the SNES "S-DD1" add-on chip.
6
7  Based on Andreas Naive Public Domain code.
8
9***************************************************************************/
10
11
12#define SSD1_ADD(addr)\
13mmc[(addr >> 20) & 3] + (addr & 0x0fffff)
14
15class SDD1_IM //Input Manager
16{
17public:
18   SDD1_IM() {}
19
20   UINT32 m_byte_ptr;
21   UINT8 m_bit_count;
22
23   void IM_prepareDecomp(UINT32 in_buf);
24   UINT8 IM_getCodeword(UINT8 *ROM, UINT32 *mmc, const UINT8 code_len);
25};
26
27void SDD1_IM::IM_prepareDecomp(UINT32 in_buf)
28{
29   m_byte_ptr = in_buf;
30   m_bit_count = 4;
31}
32
33UINT8 SDD1_IM::IM_getCodeword(UINT8 *ROM, UINT32 *mmc, const UINT8 code_len)
34{
35   UINT8 codeword = ROM[SSD1_ADD(m_byte_ptr)] << m_bit_count;
36
37   ++m_bit_count;
38
39   if (codeword & 0x80)
40   {
41      codeword |= ROM[SSD1_ADD((m_byte_ptr + 1))] >> (9 - m_bit_count);
42      m_bit_count += code_len;
43   }
44
45   if (m_bit_count & 0x08)
46   {
47      m_byte_ptr++;
48      m_bit_count &= 0x07;
49   }
50
51   return codeword;
52}
53
54class SDD1_GCD //Golomb-Code Decoder
55{
56public:
57   SDD1_GCD(SDD1_IM* associatedIM)
58      : m_IM(associatedIM) { }
59
60   SDD1_IM* m_IM;
61
62   void GCD_getRunCount(UINT8 *ROM, UINT32 *mmc, UINT8 code_num, UINT8* MPScount, UINT8* LPSind);
63};
64
65void SDD1_GCD::GCD_getRunCount(UINT8 *ROM, UINT32 *mmc, UINT8 code_num, UINT8* MPScount, UINT8* LPSind)
66{
67   const UINT8 run_count[] =
68   {
69      0x00, 0x00, 0x01, 0x00, 0x03, 0x01, 0x02, 0x00,
70      0x07, 0x03, 0x05, 0x01, 0x06, 0x02, 0x04, 0x00,
71      0x0f, 0x07, 0x0b, 0x03, 0x0d, 0x05, 0x09, 0x01,
72      0x0e, 0x06, 0x0a, 0x02, 0x0c, 0x04, 0x08, 0x00,
73      0x1f, 0x0f, 0x17, 0x07, 0x1b, 0x0b, 0x13, 0x03,
74      0x1d, 0x0d, 0x15, 0x05, 0x19, 0x09, 0x11, 0x01,
75      0x1e, 0x0e, 0x16, 0x06, 0x1a, 0x0a, 0x12, 0x02,
76      0x1c, 0x0c, 0x14, 0x04, 0x18, 0x08, 0x10, 0x00,
77      0x3f, 0x1f, 0x2f, 0x0f, 0x37, 0x17, 0x27, 0x07,
78      0x3b, 0x1b, 0x2b, 0x0b, 0x33, 0x13, 0x23, 0x03,
79      0x3d, 0x1d, 0x2d, 0x0d, 0x35, 0x15, 0x25, 0x05,
80      0x39, 0x19, 0x29, 0x09, 0x31, 0x11, 0x21, 0x01,
81      0x3e, 0x1e, 0x2e, 0x0e, 0x36, 0x16, 0x26, 0x06,
82      0x3a, 0x1a, 0x2a, 0x0a, 0x32, 0x12, 0x22, 0x02,
83      0x3c, 0x1c, 0x2c, 0x0c, 0x34, 0x14, 0x24, 0x04,
84      0x38, 0x18, 0x28, 0x08, 0x30, 0x10, 0x20, 0x00,
85      0x7f, 0x3f, 0x5f, 0x1f, 0x6f, 0x2f, 0x4f, 0x0f,
86      0x77, 0x37, 0x57, 0x17, 0x67, 0x27, 0x47, 0x07,
87      0x7b, 0x3b, 0x5b, 0x1b, 0x6b, 0x2b, 0x4b, 0x0b,
88      0x73, 0x33, 0x53, 0x13, 0x63, 0x23, 0x43, 0x03,
89      0x7d, 0x3d, 0x5d, 0x1d, 0x6d, 0x2d, 0x4d, 0x0d,
90      0x75, 0x35, 0x55, 0x15, 0x65, 0x25, 0x45, 0x05,
91      0x79, 0x39, 0x59, 0x19, 0x69, 0x29, 0x49, 0x09,
92      0x71, 0x31, 0x51, 0x11, 0x61, 0x21, 0x41, 0x01,
93      0x7e, 0x3e, 0x5e, 0x1e, 0x6e, 0x2e, 0x4e, 0x0e,
94      0x76, 0x36, 0x56, 0x16, 0x66, 0x26, 0x46, 0x06,
95      0x7a, 0x3a, 0x5a, 0x1a, 0x6a, 0x2a, 0x4a, 0x0a,
96      0x72, 0x32, 0x52, 0x12, 0x62, 0x22, 0x42, 0x02,
97      0x7c, 0x3c, 0x5c, 0x1c, 0x6c, 0x2c, 0x4c, 0x0c,
98      0x74, 0x34, 0x54, 0x14, 0x64, 0x24, 0x44, 0x04,
99      0x78, 0x38, 0x58, 0x18, 0x68, 0x28, 0x48, 0x08,
100      0x70, 0x30, 0x50, 0x10, 0x60, 0x20, 0x40, 0x00,
101   };
102
103   UINT8 codeword = m_IM->IM_getCodeword(ROM, mmc, code_num);
104
105   if (codeword & 0x80)
106   {
107      *LPSind = 1;
108      *MPScount = run_count[codeword >> (code_num ^ 0x07)];
109   }
110   else
111   {
112      *MPScount = (1 << code_num);
113   }
114}
115
116class SDD1_BG // Bits Generator
117{
118public:
119   SDD1_BG(SDD1_GCD* associatedGCD, UINT8 code)
120      : m_code_num(code),
121         m_GCD(associatedGCD) { }
122
123   UINT8 m_code_num;
124   UINT8 m_MPScount;
125   UINT8 m_LPSind;
126   SDD1_GCD* m_GCD;
127
128   void BG_prepareDecomp();
129   UINT8 BG_getBit(UINT8 *ROM, UINT32 *mmc, UINT8* endOfRun);
130} ;
131
132void SDD1_BG::BG_prepareDecomp()
133{
134   m_MPScount = 0;
135   m_LPSind = 0;
136}
137
138UINT8 SDD1_BG::BG_getBit(UINT8 *ROM, UINT32 *mmc, UINT8* endOfRun)
139{
140   UINT8 bit;
141
142   if (!(m_MPScount || m_LPSind))
143   {
144      m_GCD->GCD_getRunCount(ROM, mmc, m_code_num, &(m_MPScount), &(m_LPSind));
145   }
146
147   if (m_MPScount)
148   {
149      bit = 0;
150      m_MPScount--;
151   }
152   else
153   {
154      bit = 1;
155      m_LPSind = 0;
156   }
157
158   if (m_MPScount || m_LPSind)
159   {
160      (*endOfRun) = 0;
161   }
162   else
163   {
164      (*endOfRun) = 1;
165   }
166
167   return bit;
168}
169
170
171struct SDD1_PEM_state
172{
173   UINT8 code_num;
174   UINT8 nextIfMPS;
175   UINT8 nextIfLPS;
176};
177
178static const SDD1_PEM_state PEM_evolution_table[33] =
179{
180   { 0,25,25},
181   { 0, 2, 1},
182   { 0, 3, 1},
183   { 0, 4, 2},
184   { 0, 5, 3},
185   { 1, 6, 4},
186   { 1, 7, 5},
187   { 1, 8, 6},
188   { 1, 9, 7},
189   { 2,10, 8},
190   { 2,11, 9},
191   { 2,12,10},
192   { 2,13,11},
193   { 3,14,12},
194   { 3,15,13},
195   { 3,16,14},
196   { 3,17,15},
197   { 4,18,16},
198   { 4,19,17},
199   { 5,20,18},
200   { 5,21,19},
201   { 6,22,20},
202   { 6,23,21},
203   { 7,24,22},
204   { 7,24,23},
205   { 0,26, 1},
206   { 1,27, 2},
207   { 2,28, 4},
208   { 3,29, 8},
209   { 4,30,12},
210   { 5,31,16},
211   { 6,32,18},
212   { 7,24,22}
213};
214
215struct SDD1_PEM_ContextInfo
216{
217   UINT8 status;
218   UINT8 MPS;
219};
220
221class SDD1_PEM //Probability Estimation Module
222{
223public:
224   SDD1_PEM(
225         SDD1_BG* associatedBG0, SDD1_BG* associatedBG1,
226         SDD1_BG* associatedBG2, SDD1_BG* associatedBG3,
227         SDD1_BG* associatedBG4, SDD1_BG* associatedBG5,
228         SDD1_BG* associatedBG6, SDD1_BG* associatedBG7)
229   {
230      m_BG[0] = associatedBG0;
231      m_BG[1] = associatedBG1;
232      m_BG[2] = associatedBG2;
233      m_BG[3] = associatedBG3;
234      m_BG[4] = associatedBG4;
235      m_BG[5] = associatedBG5;
236      m_BG[6] = associatedBG6;
237      m_BG[7] = associatedBG7;
238   }
239
240   SDD1_PEM_ContextInfo m_contextInfo[32];
241   SDD1_BG* m_BG[8];
242
243   void PEM_prepareDecomp();
244   UINT8 PEM_getBit(UINT8 *ROM, UINT32 *mmc, UINT8 context);
245} ;
246
247void SDD1_PEM::PEM_prepareDecomp()
248{
249   for (int i = 0; i < 32; i++)
250   {
251      m_contextInfo[i].status = 0;
252      m_contextInfo[i].MPS = 0;
253   }
254}
255
256UINT8 SDD1_PEM::PEM_getBit(UINT8 *ROM, UINT32 *mmc, UINT8 context)
257{
258   UINT8 endOfRun;
259   UINT8 bit;
260
261   SDD1_PEM_ContextInfo *pContInfo = &(m_contextInfo)[context];
262   UINT8 currStatus = pContInfo->status;
263   const SDD1_PEM_state* pState = &(PEM_evolution_table[currStatus]);
264   UINT8 currentMPS = pContInfo->MPS;
265
266   bit = m_BG[pState->code_num]->BG_getBit(ROM, mmc, &endOfRun);
267
268   if (endOfRun)
269   {
270      if (bit)
271      {
272         if (!(currStatus & 0xfe))
273         {
274            (pContInfo->MPS) ^= 0x01;
275         }
276         pContInfo->status = pState->nextIfLPS;
277      }
278      else
279      {
280         pContInfo->status = pState->nextIfMPS;
281      }
282   }
283
284   return bit ^ currentMPS;
285}
286
287class SDD1_CM
288{
289public:
290   SDD1_CM(SDD1_PEM* associatedPEM)
291      : m_PEM(associatedPEM) { }
292
293   UINT8 m_bitplanesInfo;
294   UINT8 m_contextBitsInfo;
295   UINT8 m_bit_number;
296   UINT8 m_currBitplane;
297   UINT16 m_prevBitplaneBits[8];
298   SDD1_PEM* m_PEM;
299
300   void CM_prepareDecomp(UINT8 *ROM, UINT32 *mmc, UINT32 first_byte);
301   UINT8 CM_getBit(UINT8 *ROM, UINT32 *mmc);
302} ;
303
304void SDD1_CM::CM_prepareDecomp(UINT8 *ROM, UINT32 *mmc, UINT32 first_byte)
305{
306   INT32 i = 0;
307   m_bitplanesInfo = ROM[SSD1_ADD(first_byte)] & 0xc0;
308   m_contextBitsInfo = ROM[SSD1_ADD(first_byte)] & 0x30;
309   m_bit_number = 0;
310   for (i = 0; i < 8; i++)
311   {
312      m_prevBitplaneBits[i] = 0;
313   }
314   switch (m_bitplanesInfo)
315   {
316      case 0x00:
317         m_currBitplane = 1;
318         break;
319      case 0x40:
320         m_currBitplane = 7;
321         break;
322      case 0x80:
323         m_currBitplane = 3;
324         break;
325   }
326}
327
328UINT8 SDD1_CM::CM_getBit(UINT8 *ROM, UINT32 *mmc)
329{
330   UINT8 currContext;
331   UINT16 *context_bits;
332   UINT8 bit = 0;
333
334   switch (m_bitplanesInfo)
335   {
336      case 0x00:
337         m_currBitplane ^= 0x01;
338         break;
339      case 0x40:
340         m_currBitplane ^= 0x01;
341         if (!(m_bit_number & 0x7f))
342            m_currBitplane = ((m_currBitplane + 2) & 0x07);
343         break;
344      case 0x80:
345         m_currBitplane ^= 0x01;
346         if (!(m_bit_number & 0x7f))
347            m_currBitplane ^= 0x02;
348         break;
349      case 0xc0:
350         m_currBitplane = m_bit_number & 0x07;
351         break;
352   }
353
354   context_bits = &(m_prevBitplaneBits)[m_currBitplane];
355
356   currContext = (m_currBitplane & 0x01) << 4;
357   switch (m_contextBitsInfo)
358   {
359      case 0x00:
360         currContext |= ((*context_bits & 0x01c0) >> 5) | (*context_bits & 0x0001);
361         break;
362      case 0x10:
363         currContext |= ((*context_bits & 0x0180) >> 5) | (*context_bits & 0x0001);
364         break;
365      case 0x20:
366         currContext |= ((*context_bits & 0x00c0) >> 5) | (*context_bits & 0x0001);
367         break;
368      case 0x30:
369         currContext |= ((*context_bits & 0x0180) >> 5) | (*context_bits & 0x0003);
370         break;
371   }
372
373   bit = m_PEM->PEM_getBit(ROM, mmc, currContext);
374
375   *context_bits <<= 1;
376   *context_bits |= bit;
377
378   m_bit_number++;
379
380   return bit;
381}
382
383class SDD1_OL
384{
385public:
386   SDD1_OL(SDD1_CM* associatedCM)
387      : m_CM(associatedCM) { }
388
389   UINT8 m_bitplanesInfo;
390   UINT16 m_length;
391   UINT8* m_buffer;
392   SDD1_CM* m_CM;
393
394   void OL_prepareDecomp(UINT8 *ROM, UINT32 *mmc, UINT32 first_byte, UINT16 out_len, UINT8 *out_buf);
395   void OL_launch(UINT8 *ROM, UINT32 *mmc);
396} ;
397
398void SDD1_OL::OL_prepareDecomp(UINT8 *ROM, UINT32 *mmc, UINT32 first_byte, UINT16 out_len, UINT8 *out_buf)
399{
400   m_bitplanesInfo = ROM[SSD1_ADD(first_byte)] & 0xc0;
401   m_length = out_len;
402   m_buffer = out_buf;
403}
404
405void SDD1_OL::OL_launch(UINT8 *ROM, UINT32 *mmc)
406{
407   UINT8 i;
408   UINT8 register1 = 0, register2 = 0;
409
410   switch (m_bitplanesInfo)
411   {
412      case 0x00:
413      case 0x40:
414      case 0x80:
415         i = 1;
416         do
417         {   // if length == 0, we output 2^16 bytes
418            if (!i)
419            {
420               *(m_buffer++) = register2;
421               i = ~i;
422            }
423            else
424            {
425               for (register1 = register2 = 0, i = 0x80; i; i >>= 1)
426               {
427                  if (m_CM->CM_getBit(ROM, mmc))
428                     register1 |= i;
429
430                  if (m_CM->CM_getBit(ROM, mmc))
431                     register2 |= i;
432               }
433               *(m_buffer++) = register1;
434            }
435         } while (--(m_length));
436         break;
437      case 0xc0:
438         do
439         {
440            for (register1 = 0, i = 0x01; i; i <<= 1)
441            {
442               if (m_CM->CM_getBit(ROM, mmc))
443               {
444                  register1 |= i;
445               }
446            }
447            *(m_buffer++) = register1;
448         } while (--(m_length));
449         break;
450   }
451}
452
453class SDD1emu
454{
455public:
456   SDD1emu(running_machine &machine);
457
458   running_machine &machine() const { return m_machine; }
459
460   SDD1_IM* m_IM;
461   SDD1_GCD* m_GCD;
462   SDD1_BG* m_BG0;   SDD1_BG* m_BG1;   SDD1_BG* m_BG2;   SDD1_BG* m_BG3;
463   SDD1_BG* m_BG4;   SDD1_BG* m_BG5;   SDD1_BG* m_BG6;   SDD1_BG* m_BG7;
464   SDD1_PEM* m_PEM;
465   SDD1_CM* m_CM;
466   SDD1_OL* m_OL;
467
468   void SDD1emu_decompress(UINT8 *ROM, UINT32 *mmc, UINT32 in_buf, UINT16 out_len, UINT8 *out_buf);
469
470private:
471   running_machine& m_machine;
472};
473
474SDD1emu::SDD1emu(running_machine &machine)
475   : m_machine(machine)
476{
477   m_IM = auto_alloc(machine, SDD1_IM());
478   m_GCD = auto_alloc(machine, SDD1_GCD(m_IM));
479   m_BG0 = auto_alloc(machine, SDD1_BG(m_GCD, 0));
480   m_BG1 = auto_alloc(machine, SDD1_BG(m_GCD, 1));
481   m_BG2 = auto_alloc(machine, SDD1_BG(m_GCD, 2));
482   m_BG3 = auto_alloc(machine, SDD1_BG(m_GCD, 3));
483   m_BG4 = auto_alloc(machine, SDD1_BG(m_GCD, 4));
484   m_BG5 = auto_alloc(machine, SDD1_BG(m_GCD, 5));
485   m_BG6 = auto_alloc(machine, SDD1_BG(m_GCD, 6));
486   m_BG7 = auto_alloc(machine, SDD1_BG(m_GCD, 7));
487   m_PEM = auto_alloc(machine, SDD1_PEM(m_BG0, m_BG1, m_BG2, m_BG3,
488                                 m_BG4, m_BG5, m_BG6, m_BG7));
489   m_CM = auto_alloc(machine, SDD1_CM(m_PEM));
490   m_OL = auto_alloc(machine, SDD1_OL(m_CM));
491}
492
493void SDD1emu::SDD1emu_decompress(UINT8 *ROM, UINT32 *mmc, UINT32 in_buf, UINT16 out_len, UINT8 *out_buf)
494{
495   m_IM->IM_prepareDecomp(in_buf);
496   m_BG0->BG_prepareDecomp();
497   m_BG1->BG_prepareDecomp();
498   m_BG2->BG_prepareDecomp();
499   m_BG3->BG_prepareDecomp();
500   m_BG4->BG_prepareDecomp();
501   m_BG5->BG_prepareDecomp();
502   m_BG6->BG_prepareDecomp();
503   m_BG7->BG_prepareDecomp();
504   m_PEM->PEM_prepareDecomp();
505   m_CM->CM_prepareDecomp(ROM, mmc, in_buf);
506   m_OL->OL_prepareDecomp(ROM, mmc, in_buf, out_len, out_buf);
507
508   m_OL->OL_launch(ROM, mmc);
509}
510
511struct snes_sdd1_t
512{
513   UINT8 sdd1_enable;  // channel bit-mask
514   UINT8 xfer_enable;  // channel bit-mask
515   UINT32 mmc[4];      // memory map controller ROM indices
516
517   struct
518   {
519      UINT32 addr;    // $43x2-$43x4 -- DMA transfer address
520      UINT16 size;    // $43x5-$43x6 -- DMA transfer size
521   } dma[8];
522
523   SDD1emu* sdd1emu;
524   struct
525   {
526      UINT8 *data;    // pointer to decompressed S-DD1 data (65536 bytes)
527      UINT16 offset;  // read index into S-DD1 decompression buffer
528      UINT32 size;    // length of data buffer; reads decrement counter, set ready to false at 0
529      UINT8 ready;    // 1 when data[] is valid; 0 to invoke sdd1emu.decompress()
530   } buffer;
531} ;
532
533static snes_sdd1_t snes_sdd1;
534
535void sdd1_init(running_machine& machine)
536{
537   snes_sdd1.sdd1_enable = 0x00;
538   snes_sdd1.xfer_enable = 0x00;
539
540   snes_sdd1.mmc[0] = 0 << 20;
541   snes_sdd1.mmc[1] = 1 << 20;
542   snes_sdd1.mmc[2] = 2 << 20;
543   snes_sdd1.mmc[3] = 3 << 20;
544
545   for (int i = 0; i < 8; i++)
546   {
547      snes_sdd1.dma[i].addr = 0;
548      snes_sdd1.dma[i].size = 0;
549   }
550
551   snes_sdd1.sdd1emu = auto_alloc(machine, SDD1emu(machine));
552
553   snes_sdd1.buffer.data = (UINT8*)auto_alloc_array(machine, UINT8, 0x10000);
554   snes_sdd1.buffer.ready = 0;
555}
556
557UINT8 sdd1_mmio_read(address_space &space, UINT32 addr)
558{
559   addr &= 0xffff;
560
561   switch(addr)
562   {
563      case 0x4804:
564         return (snes_sdd1.mmc[0] >> 20) & 7;
565      case 0x4805:
566         return (snes_sdd1.mmc[1] >> 20) & 7;
567      case 0x4806:
568         return (snes_sdd1.mmc[2] >> 20) & 7;
569      case 0x4807:
570         return (snes_sdd1.mmc[3] >> 20) & 7;
571   }
572
573   return snes_open_bus_r(space, 0);
574}
575
576void sdd1_mmio_write(address_space &space, UINT32 addr, UINT8 data)
577{
578   addr &= 0xffff;
579
580   if ((addr & 0x4380) == 0x4300)
581   {
582      UINT8 channel = (addr >> 4) & 7;
583      switch(addr & 15)
584      {
585         case 2:
586            snes_sdd1.dma[channel].addr = (snes_sdd1.dma[channel].addr & 0xffff00) + (data <<  0);
587            break;
588         case 3:
589            snes_sdd1.dma[channel].addr = (snes_sdd1.dma[channel].addr & 0xff00ff) + (data <<  8);
590            break;
591         case 4:
592            snes_sdd1.dma[channel].addr = (snes_sdd1.dma[channel].addr & 0x00ffff) + (data << 16);
593            break;
594
595         case 5:
596            snes_sdd1.dma[channel].size = (snes_sdd1.dma[channel].size &   0xff00) + (data <<  0);
597            break;
598         case 6:
599            snes_sdd1.dma[channel].size = (snes_sdd1.dma[channel].size &   0x00ff) + (data <<  8);
600            break;
601      }
602      return;
603   }
604
605   switch(addr)
606   {
607      case 0x4800:
608         snes_sdd1.sdd1_enable = data;
609         break;
610      case 0x4801:
611         snes_sdd1.xfer_enable = data;
612         break;
613
614      case 0x4804:
615         snes_sdd1.mmc[0] = (data & 7) << 20;
616         break;
617      case 0x4805:
618         snes_sdd1.mmc[1] = (data & 7) << 20;
619         break;
620      case 0x4806:
621         snes_sdd1.mmc[2] = (data & 7) << 20;
622         break;
623      case 0x4807:
624         snes_sdd1.mmc[3] = (data & 7) << 20;
625         break;
626   }
627}
628
629UINT8 sdd1_read(running_machine& machine, UINT32 addr)
630{
631   unsigned char *ROM = machine.root_device().memregion("cart")->base();
632
633   if (snes_sdd1.sdd1_enable & snes_sdd1.xfer_enable)
634   {
635      // at least one channel has S-DD1 decompression enabled...
636      for (int i = 0; i < 8; i++)
637      {
638         if (snes_sdd1.sdd1_enable & snes_sdd1.xfer_enable & (1 << i))
639         {
640            // S-DD1 always uses fixed transfer mode, so address will not change during transfer
641            if ((addr + 0xc00000) == snes_sdd1.dma[i].addr)
642            {
643               UINT8 data;
644               if (!snes_sdd1.buffer.ready)
645               {
646                  UINT8 temp;
647                  // first byte read for channel performs full decompression.
648                  // this really should stream byte-by-byte, but it's not necessary since the size is known
649                  snes_sdd1.buffer.offset = 0;
650                  snes_sdd1.buffer.size = snes_sdd1.dma[i].size ? snes_sdd1.dma[i].size : 65536;
651
652                  // sdd1emu calls this function; it needs to access uncompressed data;
653                  // so temporarily disable decompression mode for decompress() call.
654                  temp = snes_sdd1.sdd1_enable;
655                  snes_sdd1.sdd1_enable = 0;
656                  snes_sdd1.sdd1emu->SDD1emu_decompress(ROM, snes_sdd1.mmc, addr, snes_sdd1.buffer.size, snes_sdd1.buffer.data);
657                  snes_sdd1.sdd1_enable = temp;
658
659                  snes_sdd1.buffer.ready = 1;
660               }
661
662               // fetch a decompressed byte; once buffer is depleted, disable channel and invalidate buffer
663               data = snes_sdd1.buffer.data[(UINT16)snes_sdd1.buffer.offset++];
664               if (snes_sdd1.buffer.offset >= snes_sdd1.buffer.size)
665               {
666                  snes_sdd1.buffer.ready = 0;
667                  snes_sdd1.xfer_enable &= ~(1 << i);
668               }
669
670               return data;
671            } // address matched
672         } // channel enabled
673      } // channel loop
674   } // S-DD1 decompressor enabled
675
676   return ROM[snes_sdd1.mmc[(addr >> 20) & 3] + (addr & 0x0fffff)];
677}
Property changes on: trunk/src/mess/machine/snessdd1.c
Added: svn:mime-type
   + text/plain
Added: svn:eol-style
   + native
trunk/src/mess/machine/snesobc1.c
r0r21590
1/***************************************************************************
2
3  snesobc1.c
4
5  File to handle emulation of the SNES "OBC-1" add-on chip.
6
7  Original C++ code by byuu.
8  Byuu's code is released under GNU General Public License
9  version 2 as published by the Free Software Foundation.
10  The implementation below is released under the MAME license
11  for use in MAME, MESS and derivatives by permission of the author.
12
13***************************************************************************/
14
15struct snes_obc1_state
16{
17   int address;
18   int offset;
19   int shift;
20};
21
22static snes_obc1_state obc1_state;
23
24
25READ8_HANDLER( obc1_read )
26{
27   UINT16 address = offset & 0x1fff;
28   UINT8 value;
29
30   switch (address)
31   {
32      case 0x1ff0:
33         value = snes_ram[obc1_state.offset + (obc1_state.address << 2) + 0];
34         break;
35
36      case 0x1ff1:
37         value = snes_ram[obc1_state.offset + (obc1_state.address << 2) + 1];
38         break;
39
40      case 0x1ff2:
41         value = snes_ram[obc1_state.offset + (obc1_state.address << 2) + 2];
42         break;
43
44      case 0x1ff3:
45         value = snes_ram[obc1_state.offset + (obc1_state.address << 2) + 3];
46         break;
47
48      case 0x1ff4:
49         value = snes_ram[obc1_state.offset + (obc1_state.address >> 2) + 0x200];
50         break;
51
52      default:
53         value = snes_ram[address];
54         break;
55   }
56
57   return value;
58}
59
60
61WRITE8_HANDLER( obc1_write )
62{
63   UINT16 address = offset & 0x1fff;
64   UINT8 temp;
65
66   switch(address)
67   {
68      case 0x1ff0:
69         snes_ram[obc1_state.offset + (obc1_state.address << 2) + 0] = data;
70         break;
71
72      case 0x1ff1:
73         snes_ram[obc1_state.offset + (obc1_state.address << 2) + 1] = data;
74         break;
75
76      case 0x1ff2:
77         snes_ram[obc1_state.offset + (obc1_state.address << 2) + 2] = data;
78         break;
79
80      case 0x1ff3:
81         snes_ram[obc1_state.offset + (obc1_state.address << 2) + 3] = data;
82         break;
83
84      case 0x1ff4:
85         temp = snes_ram[obc1_state.offset + (obc1_state.address >> 2) + 0x200];
86         temp = (temp & ~(3 << obc1_state.shift)) | ((data & 0x03) << obc1_state.shift);
87         snes_ram[obc1_state.offset + (obc1_state.address >> 2) + 0x200] = temp;
88         break;
89
90      case 0x1ff5:
91         obc1_state.offset = (data & 0x01) ? 0x1800 : 0x1c00;
92         snes_ram[address & 0x1fff] = data;
93         break;
94
95      case 0x1ff6:
96         obc1_state.address = data & 0x7f;
97         obc1_state.shift = (data & 0x03) << 1;
98         snes_ram[address & 0x1fff] = data;
99         break;
100
101      default:
102         snes_ram[address & 0x1fff] = data;
103         break;
104   }
105}
106
107void obc1_init( running_machine &machine )
108{
109   obc1_state.offset  = (snes_ram[0x1ff5] & 0x01) ? 0x1800 : 0x1c00;
110   obc1_state.address = (snes_ram[0x1ff6] & 0x7f);
111   obc1_state.shift   = (snes_ram[0x1ff6] & 0x03) << 1;
112
113   state_save_register_global(machine, obc1_state.offset);
114   state_save_register_global(machine, obc1_state.address);
115   state_save_register_global(machine, obc1_state.shift);
116}
Property changes on: trunk/src/mess/machine/snesobc1.c
Added: svn:mime-type
   + text/plain
Added: svn:eol-style
   + native
trunk/src/mess/machine/snesrtc.c
r0r21590
1/***************************************************************************
2
3  snesrtc.c
4
5  File to handle emulation of the SNES "S-RTC" add-on chip.
6
7  Based on C++ implementation by Byuu in BSNES.
8
9  Byuu's code is released under GNU General Public License
10  version 2 as published by the Free Software Foundation.
11  The implementation below is released under the MAME license
12  for use in MAME, MESS and derivatives by permission of the
13  author
14
15***************************************************************************/
16
17enum
18{
19   RTCM_Ready,
20   RTCM_Command,
21   RTCM_Read,
22   RTCM_Write
23};
24
25struct snes_rtc_state
26{
27   UINT8  ram[13];
28   INT32  mode;
29   INT8   index;
30};
31
32static snes_rtc_state rtc_state;
33
34static const UINT8 srtc_months[12] =
35{
36   31, 28, 31,
37   30, 31, 30,
38   31, 31, 30,
39   31, 30, 31
40};
41
42static void srtc_update_time( running_machine &machine )
43{
44   system_time curtime, *systime = &curtime;
45   machine.current_datetime(curtime);
46   rtc_state.ram[0] = systime->local_time.second % 10;
47   rtc_state.ram[1] = systime->local_time.second / 10;
48   rtc_state.ram[2] = systime->local_time.minute % 10;
49   rtc_state.ram[3] = systime->local_time.minute / 10;
50   rtc_state.ram[4] = systime->local_time.hour % 10;
51   rtc_state.ram[5] = systime->local_time.hour / 10;
52   rtc_state.ram[6] = systime->local_time.mday % 10;
53   rtc_state.ram[7] = systime->local_time.mday / 10;
54   rtc_state.ram[8] = systime->local_time.month;
55   rtc_state.ram[9] = (systime->local_time.year - 1000) % 10;
56   rtc_state.ram[10] = ((systime->local_time.year - 1000) / 10) % 10;
57   rtc_state.ram[11] = (systime->local_time.year - 1000) / 100;
58   rtc_state.ram[12] = systime->local_time.weekday % 7;
59}
60
61// Returns day-of-week for specified date
62// e.g. 0 = Sunday, 1 = Monday, ... 6 = Saturday
63// Usage: weekday(2008, 1, 1) returns the weekday of January 1st, 2008
64static UINT8 srtc_weekday( UINT32 year, UINT32 month, UINT32 day )
65{
66   UINT32 y = 1900, m = 1; // Epoch is 1900-01-01
67   UINT32 sum = 0;         // Number of days passed since epoch
68
69   year = MAX(1900, year);
70   month = MAX(1, MIN(12, month));
71   day = MAX(1, MIN(31, day));
72
73   while (y < year)
74   {
75      UINT8 leapyear = 0;
76      if ((y % 4) == 0)
77      {
78         leapyear = 1;
79         if ((y % 100) == 0 && (y % 400) != 0)
80         {
81            leapyear = 0;
82         }
83      }
84      sum += leapyear ? 366 : 365;
85      y++;
86   }
87
88   while (m < month)
89   {
90      UINT32 days = srtc_months[m - 1];
91      if (days == 28)
92      {
93         UINT8 leapyear = 0;
94         if ((y % 4) == 0)
95         {
96            leapyear = 1;
97            if ((y % 100) == 0 && (y % 400) != 0)
98            {
99               leapyear = 0;
100            }
101         }
102         days += leapyear ? 1 : 0;
103      }
104      sum += days;
105      m++;
106   }
107
108   sum += day - 1;
109   return (sum + 1) % 7; // 1900-01-01 was a Monday
110}
111
112UINT8 srtc_read( address_space &space, UINT16 addr )
113{
114   addr &= 0xffff;
115
116   if (addr == 0x2800)
117   {
118      if (rtc_state.mode != RTCM_Read)
119      {
120         return 0x00;
121      }
122
123      if (rtc_state.index < 0)
124      {
125         srtc_update_time(space.machine());
126         rtc_state.index++;
127         return 0x0f;
128      }
129      else if (rtc_state.index > 12)
130      {
131         rtc_state.index = -1;
132         return 0x0f;
133      }
134      else
135      {
136         return rtc_state.ram[rtc_state.index++];
137      }
138   }
139
140   return snes_open_bus_r(space, 0);
141}
142
143void srtc_write( running_machine &machine, UINT16 addr, UINT8 data )
144{
145   addr &= 0xffff;
146
147   if (addr == 0x2801)
148   {
149      data &= 0x0f;   // Only the low four bits are used
150
151      if (data == 0x0d)
152      {
153         rtc_state.mode = RTCM_Read;
154         rtc_state.index = -1;
155         return;
156      }
157
158      if (data == 0x0e)
159      {
160         rtc_state.mode = RTCM_Command;
161         return;
162      }
163
164      if (data == 0x0f)
165      {
166         return; // Unknown behaviour
167      }
168
169      if (rtc_state.mode == RTCM_Write)
170      {
171         if (rtc_state.index >= 0 && rtc_state.index < 12)
172         {
173            rtc_state.ram[rtc_state.index++] = data;
174
175            if (rtc_state.index == 12)
176            {
177               // Day of week is automatically calculated and written
178               UINT32 day   = rtc_state.ram[6] + rtc_state.ram[7] * 10;
179               UINT32 month = rtc_state.ram[8];
180               UINT32 year  = rtc_state.ram[9] + rtc_state.ram[10] * 10 + rtc_state.ram[11] * 100;
181               year += 1000;
182
183               rtc_state.ram[rtc_state.index++] = srtc_weekday(year, month, day);
184            }
185         }
186      }
187      else if (rtc_state.mode == RTCM_Command)
188      {
189         if (data == 0)
190         {
191            rtc_state.mode = RTCM_Write;
192            rtc_state.index = 0;
193         }
194         else if (data == 4)
195         {
196            UINT8 i;
197            rtc_state.mode = RTCM_Ready;
198            rtc_state.index = -1;
199            for(i = 0; i < 13; i++)
200            {
201               rtc_state.ram[i] = 0;
202            }
203         }
204         else
205         {
206            // Unknown behaviour
207            rtc_state.mode = RTCM_Ready;
208         }
209      }
210   }
211}
212
213void srtc_init( running_machine &machine )
214{
215   rtc_state.mode = RTCM_Read;
216   rtc_state.index = -1;
217   srtc_update_time(machine);
218
219   state_save_register_global_array(machine, rtc_state.ram);
220   state_save_register_global(machine, rtc_state.mode);
221   state_save_register_global(machine, rtc_state.index);
222}
Property changes on: trunk/src/mess/machine/snesrtc.c
Added: svn:eol-style
   + native
Added: svn:mime-type
   + text/plain
trunk/src/mess/machine/cx4ops.c
r0r21590
1/***************************************************************************
2
3    cx4ops.c
4
5    Code based on original work by zsKnight, anomie and Nach.
6    This implementation is based on C++ "cx4*.cpp" by byuu
7    (up to date with source v 0.49).
8
9***************************************************************************/
10
11//Sprite Functions
12static void CX4_op00(running_machine& machine)
13{
14   switch(cx4.reg[0x4d])
15   {
16      case 0x00: CX4_op00_00(machine); break;
17      case 0x03: CX4_op00_03(); break;
18      case 0x05: CX4_op00_05(machine); break;
19      case 0x07: CX4_op00_07(); break;
20      case 0x08: CX4_op00_08(machine); break;
21      case 0x0b: CX4_op00_0b(machine); break;
22      case 0x0c: CX4_op00_0c(machine); break;
23   }
24}
25
26//Draw Wireframe
27static void CX4_op01(running_machine& machine)
28{
29   memset(cx4.ram + 0x300, 0, 2304);
30   CX4_C4DrawWireFrame(machine);
31}
32
33//Propulsion
34static void CX4_op05(running_machine &machine)
35{
36   INT32 temp = 0x10000;
37   if(CX4_readw(0x1f83))
38   {
39      temp = CX4_sar((temp / CX4_readw(0x1f83)) * CX4_readw(0x1f81), 8);
40   }
41   CX4_writew(machine, 0x1f80, temp);
42}
43
44//Set Vector length
45static void CX4_op0d(running_machine &machine)
46{
47   cx4.C41FXVal    = CX4_readw(0x1f80);
48   cx4.C41FYVal    = CX4_readw(0x1f83);
49   cx4.C41FDistVal = CX4_readw(0x1f86);
50   cx4.tanval = sqrt(((double)cx4.C41FYVal) * ((double)cx4.C41FYVal) + ((double)cx4.C41FXVal) * ((double)cx4.C41FXVal));
51   cx4.tanval = (double)cx4.C41FDistVal / cx4.tanval;
52   cx4.C41FYVal = (INT16)(((double)cx4.C41FYVal * cx4.tanval) * 0.99);
53   cx4.C41FXVal = (INT16)(((double)cx4.C41FXVal * cx4.tanval) * 0.98);
54   CX4_writew(machine, 0x1f89, cx4.C41FXVal);
55   CX4_writew(machine, 0x1f8c, cx4.C41FYVal);
56}
57
58//Triangle
59static void CX4_op10(void)
60{
61   cx4.r0 = CX4_ldr(0);
62   cx4.r1 = CX4_ldr(1);
63
64   cx4.r4 = cx4.r0 & 0x1ff;
65   if(cx4.r1 & 0x8000)
66   {
67      cx4.r1 |= ~0x7fff;
68   }
69
70   CX4_mul(CX4_cos(cx4.r4), cx4.r1, &cx4.r5, &cx4.r2);
71   cx4.r5 = (cx4.r5 >> 16) & 0xff;
72   cx4.r2 = (cx4.r2 << 8) + cx4.r5;
73
74   CX4_mul(CX4_sin(cx4.r4), cx4.r1, &cx4.r5, &cx4.r3);
75   cx4.r5 = (cx4.r5 >> 16) & 0xff;
76   cx4.r3 = (cx4.r3 << 8) + cx4.r5;
77
78   CX4_str(0, cx4.r0);
79   CX4_str(1, cx4.r1);
80   CX4_str(2, cx4.r2);
81   CX4_str(3, cx4.r3);
82   CX4_str(4, cx4.r4);
83   CX4_str(5, cx4.r5);
84}
85
86//Triangle
87static void CX4_op13(void)
88{
89   cx4.r0 = CX4_ldr(0);
90   cx4.r1 = CX4_ldr(1);
91
92   cx4.r4 = cx4.r0 & 0x1ff;
93
94   CX4_mul(CX4_cos(cx4.r4), cx4.r1, &cx4.r5, &cx4.r2);
95   cx4.r5 = (cx4.r5 >> 8) & 0xffff;
96   cx4.r2 = (cx4.r2 << 16) + cx4.r5;
97
98   CX4_mul(CX4_sin(cx4.r4), cx4.r1, &cx4.r5, &cx4.r3);
99   cx4.r5 = (cx4.r5 >> 8) & 0xffff;
100   cx4.r3 = (cx4.r3 << 16) + cx4.r5;
101
102   CX4_str(0, cx4.r0);
103   CX4_str(1, cx4.r1);
104   CX4_str(2, cx4.r2);
105   CX4_str(3, cx4.r3);
106   CX4_str(4, cx4.r4);
107   CX4_str(5, cx4.r5);
108}
109
110//Pythagorean
111static void CX4_op15(running_machine &machine)
112{
113   double temp = 0.0;
114   cx4.C41FXVal = CX4_readw(0x1f80);
115   cx4.C41FYVal = CX4_readw(0x1f83);
116   temp = sqrt((double)cx4.C41FXVal * (double)cx4.C41FXVal + (double)cx4.C41FYVal * (double)cx4.C41FYVal);
117   cx4.C41FDist = (INT16)temp;
118   CX4_writew(machine, 0x1f80, cx4.C41FDist);
119}
120
121//Calculate distance
122static void CX4_op1f(running_machine &machine)
123{
124   cx4.C41FXVal = CX4_readw(0x1f80);
125   cx4.C41FYVal = CX4_readw(0x1f83);
126   if(!cx4.C41FXVal)
127   {
128      cx4.C41FAngleRes = (cx4.C41FYVal > 0) ? 0x080 : 0x180;
129   }
130   else
131   {
132      cx4.tanval = ((double)cx4.C41FYVal) / ((double)cx4.C41FXVal);
133      cx4.C41FAngleRes = (INT16)(atan(cx4.tanval) / (PI * 2) * 512);
134      cx4.C41FAngleRes = cx4.C41FAngleRes;
135      if(cx4.C41FXVal < 0)
136      {
137         cx4.C41FAngleRes += 0x100;
138      }
139      cx4.C41FAngleRes &= 0x1ff;
140   }
141   CX4_writew(machine, 0x1f86, cx4.C41FAngleRes);
142}
143
144//Trapezoid
145static void CX4_op22(void)
146{
147   INT16 angle1 = CX4_readw(0x1f8c) & 0x1ff;
148   INT16 angle2 = CX4_readw(0x1f8f) & 0x1ff;
149   INT32 tan1 = CX4_Tan(angle1);
150   INT32 tan2 = CX4_Tan(angle2);
151   INT16 y = CX4_readw(0x1f83) - CX4_readw(0x1f89);
152   INT16 left, right;
153   INT32 j;
154
155   for(j = 0; j < 225; j++, y++)
156   {
157      if(y >= 0)
158      {
159         left  = CX4_sar((INT32)tan1 * y, 16) - CX4_readw(0x1f80) + CX4_readw(0x1f86);
160         right = CX4_sar((INT32)tan2 * y, 16) - CX4_readw(0x1f80) + CX4_readw(0x1f86) + CX4_readw(0x1f93);
161
162         if(left < 0 && right < 0)
163         {
164            left  = 1;
165            right = 0;
166         }
167         else if(left < 0)
168         {
169            left  = 0;
170         }
171         else if(right < 0)
172         {
173            right = 0;
174         }
175
176         if(left > 255 && right > 255)
177         {
178            left  = 255;
179            right = 254;
180         }
181         else if(left > 255)
182         {
183            left  = 255;
184         }
185         else if(right > 255)
186         {
187            right = 255;
188         }
189      }
190      else
191      {
192         left  = 1;
193         right = 0;
194      }
195      cx4.ram[j + 0x800] = (UINT8)left;
196      cx4.ram[j + 0x900] = (UINT8)right;
197   }
198}
199
200//Multiply
201static void CX4_op25(void)
202{
203   cx4.r0 = CX4_ldr(0);
204   cx4.r1 = CX4_ldr(1);
205   CX4_mul(cx4.r0, cx4.r1, &cx4.r0, &cx4.r1);
206   CX4_str(0, cx4.r0);
207   CX4_str(1, cx4.r1);
208}
209
210//Transform Coords
211static void CX4_op2d(running_machine &machine)
212{
213   cx4.C4WFXVal  = CX4_readw(0x1f81);
214   cx4.C4WFYVal  = CX4_readw(0x1f84);
215   cx4.C4WFZVal  = CX4_readw(0x1f87);
216   cx4.C4WFX2Val = CX4_read (0x1f89);
217   cx4.C4WFY2Val = CX4_read (0x1f8a);
218   cx4.C4WFDist  = CX4_read (0x1f8b);
219   cx4.C4WFScale = CX4_readw(0x1f90);
220   CX4_C4TransfWireFrame2();
221   CX4_writew(machine, 0x1f80, cx4.C4WFXVal);
222   CX4_writew(machine, 0x1f83, cx4.C4WFYVal);
223}
224
225//Sum
226static void CX4_op40(void)
227{
228   UINT32 i;
229   cx4.r0 = 0;
230   for(i=0;i<0x800;i++)
231   {
232      cx4.r0 += cx4.ram[i];
233   }
234   CX4_str(0, cx4.r0);
235}
236
237//Square
238static void CX4_op54(void)
239{
240   cx4.r0 = CX4_ldr(0);
241   CX4_mul(cx4.r0, cx4.r0, &cx4.r1, &cx4.r2);
242   CX4_str(1, cx4.r1);
243   CX4_str(2, cx4.r2);
244}
245
246//Immediate Register
247static void CX4_op5c(void)
248{
249   CX4_str(0, 0x000000);
250   CX4_immediate_reg(0);
251}
252
253//Immediate Register (Multiple)
254static void CX4_op5e(void) { CX4_immediate_reg( 0); }
255static void CX4_op60(void) { CX4_immediate_reg( 3); }
256static void CX4_op62(void) { CX4_immediate_reg( 6); }
257static void CX4_op64(void) { CX4_immediate_reg( 9); }
258static void CX4_op66(void) { CX4_immediate_reg(12); }
259static void CX4_op68(void) { CX4_immediate_reg(15); }
260static void CX4_op6a(void) { CX4_immediate_reg(18); }
261static void CX4_op6c(void) { CX4_immediate_reg(21); }
262static void CX4_op6e(void) { CX4_immediate_reg(24); }
263static void CX4_op70(void) { CX4_immediate_reg(27); }
264static void CX4_op72(void) { CX4_immediate_reg(30); }
265static void CX4_op74(void) { CX4_immediate_reg(33); }
266static void CX4_op76(void) { CX4_immediate_reg(36); }
267static void CX4_op78(void) { CX4_immediate_reg(39); }
268static void CX4_op7a(void) { CX4_immediate_reg(42); }
269static void CX4_op7c(void) { CX4_immediate_reg(45); }
270
271//Immediate ROM
272static void CX4_op89(void)
273{
274   CX4_str(0, 0x054336);
275   CX4_str(1, 0xffffff);
276}
Property changes on: trunk/src/mess/machine/cx4ops.c
Added: svn:mime-type
   + text/plain
Added: svn:eol-style
   + native
trunk/src/mess/machine/snes7110.c
r0r21590
1/***************************************************************************
2
3  snes7110.c
4
5  File to handle emulation of the SNES "SPC7110" add-on chip.
6
7  Based on C++ implementation by Byuu in BSNES.
8
9  Byuu's code is released under GNU General Public License
10  version 2 as published by the Free Software Foundation.
11  The implementation below is released under the MAME license
12  for use in MAME, MESS and derivatives by permission of the
13  author
14
15***************************************************************************/
16
17
18#define SPC7110_DECOMP_BUFFER_SIZE 64
19
20static const UINT8 spc7110_evolution_table[53][4] =
21{
22   { 0x5a,  1,  1, 1 },
23   { 0x25,  6,  2, 0 },
24   { 0x11,  8,  3, 0 },
25   { 0x08, 10,  4, 0 },
26   { 0x03, 12,  5, 0 },
27   { 0x01, 15,  5, 0 },
28
29   { 0x5a,  7,  7, 1 },
30   { 0x3f, 19,  8, 0 },
31   { 0x2c, 21,  9, 0 },
32   { 0x20, 22, 10, 0 },
33   { 0x17, 23, 11, 0 },
34   { 0x11, 25, 12, 0 },
35   { 0x0c, 26, 13, 0 },
36   { 0x09, 28, 14, 0 },
37   { 0x07, 29, 15, 0 },
38   { 0x05, 31, 16, 0 },
39   { 0x04, 32, 17, 0 },
40   { 0x03, 34, 18, 0 },
41   { 0x02, 35,  5, 0 },
42
43   { 0x5a, 20, 20, 1 },
44   { 0x48, 39, 21, 0 },
45   { 0x3a, 40, 22, 0 },
46   { 0x2e, 42, 23, 0 },
47   { 0x26, 44, 24, 0 },
48   { 0x1f, 45, 25, 0 },
49   { 0x19, 46, 26, 0 },
50   { 0x15, 25, 27, 0 },
51   { 0x11, 26, 28, 0 },
52   { 0x0e, 26, 29, 0 },
53   { 0x0b, 27, 30, 0 },
54   { 0x09, 28, 31, 0 },
55   { 0x08, 29, 32, 0 },
56   { 0x07, 30, 33, 0 },
57   { 0x05, 31, 34, 0 },
58   { 0x04, 33, 35, 0 },
59   { 0x04, 33, 36, 0 },
60   { 0x03, 34, 37, 0 },
61   { 0x02, 35, 38, 0 },
62   { 0x02, 36,  5, 0 },
63
64   { 0x58, 39, 40, 1 },
65   { 0x4d, 47, 41, 0 },
66   { 0x43, 48, 42, 0 },
67   { 0x3b, 49, 43, 0 },
68   { 0x34, 50, 44, 0 },
69   { 0x2e, 51, 45, 0 },
70   { 0x29, 44, 46, 0 },
71   { 0x25, 45, 24, 0 },
72
73   { 0x56, 47, 48, 1 },
74   { 0x4f, 47, 49, 0 },
75   { 0x47, 48, 50, 0 },
76   { 0x41, 49, 51, 0 },
77   { 0x3c, 50, 52, 0 },
78   { 0x37, 51, 43, 0 },
79};
80
81static const UINT8 spc7110_mode2_context_table[32][2] =
82{
83   {  1,  2 },
84
85   {  3,  8 },
86   { 13, 14 },
87
88   { 15, 16 },
89   { 17, 18 },
90   { 19, 20 },
91   { 21, 22 },
92   { 23, 24 },
93   { 25, 26 },
94   { 25, 26 },
95   { 25, 26 },
96   { 25, 26 },
97   { 25, 26 },
98   { 27, 28 },
99   { 29, 30 },
100
101   { 31, 31 },
102   { 31, 31 },
103   { 31, 31 },
104   { 31, 31 },
105   { 31, 31 },
106   { 31, 31 },
107   { 31, 31 },
108   { 31, 31 },
109   { 31, 31 },
110   { 31, 31 },
111   { 31, 31 },
112   { 31, 31 },
113   { 31, 31 },
114   { 31, 31 },
115   { 31, 31 },
116   { 31, 31 },
117
118   { 31, 31 },
119};
120
121class SPC7110Decomp
122{
123public:
124   SPC7110Decomp(running_machine &machine, UINT32 size);
125
126   running_machine &machine() const { return m_machine; }
127
128   void init(running_machine &machine, UINT8 *ROM, UINT32 mode, UINT32 offset, UINT32 index);
129   void reset();
130
131   UINT8 read(UINT8 *ROM);
132   void write(UINT8 data);
133   void mode0(UINT8 init, UINT8 *ROM);
134   void mode1(UINT8 init, UINT8 *ROM);
135   void mode2(UINT8 init, UINT8 *ROM);
136
137   UINT8 dataread(UINT8 *ROM);
138   UINT8 probability(UINT32 n);
139   UINT8 next_lps(UINT32 n);
140   UINT8 next_mps(UINT32 n);
141   UINT8 toggle_invert(UINT32 n);
142   UINT32 morton_2x8(UINT32 data);
143   UINT32 morton_4x8(UINT32 data);
144
145   UINT32 m_decomp_mode;
146   UINT32 m_decomp_offset;
147
148   UINT8 *m_decomp_buffer;
149   UINT32 m_decomp_buffer_rdoffset;
150   UINT32 m_decomp_buffer_wroffset;
151   UINT32 m_decomp_buffer_length;
152
153   struct ContextState
154   {
155      UINT8 index;
156      UINT8 invert;
157   } m_context[32];
158
159   UINT32 m_morton16[2][256];
160   UINT32 m_morton32[4][256];
161
162
163private:
164   running_machine& m_machine;
165   UINT32 m_rom_size;
166};
167
168SPC7110Decomp::SPC7110Decomp(running_machine &machine, UINT32 size)
169      :  m_machine(machine),
170      m_rom_size(size)
171{
172   m_decomp_buffer = (UINT8*)auto_alloc_array(machine, UINT8, SPC7110_DECOMP_BUFFER_SIZE);
173   reset();
174
175   for (int i = 0; i < 256; i++)
176   {
177      #define map(x, y) (((i >> x) & 1) << y)
178      //2x8-bit
179      m_morton16[1][i] = map(7, 15) + map(6,  7) + map(5, 14) + map(4,  6)
180                     + map(3, 13) + map(2,  5) + map(1, 12) + map(0,  4);
181      m_morton16[0][i] = map(7, 11) + map(6,  3) + map(5, 10) + map(4,  2)
182                     + map(3,  9) + map(2,  1) + map(1,  8) + map(0,  0);
183      //4x8-bit
184      m_morton32[3][i] = map(7, 31) + map(6, 23) + map(5, 15) + map(4,  7)
185                     + map(3, 30) + map(2, 22) + map(1, 14) + map(0,  6);
186      m_morton32[2][i] = map(7, 29) + map(6, 21) + map(5, 13) + map(4,  5)
187                     + map(3, 28) + map(2, 20) + map(1, 12) + map(0,  4);
188      m_morton32[1][i] = map(7, 27) + map(6, 19) + map(5, 11) + map(4,  3)
189                     + map(3, 26) + map(2, 18) + map(1, 10) + map(0,  2);
190      m_morton32[0][i] = map(7, 25) + map(6, 17) + map(5,  9) + map(4,  1)
191                     + map(3, 24) + map(2, 16) + map(1,  8) + map(0,  0);
192      #undef map
193   }
194}
195
196void SPC7110Decomp::reset()
197{
198   //mode 3 is invalid; this is treated as a special case to always return 0x00
199   //set to mode 3 so that reading decomp port before starting first decomp will return 0x00
200   m_decomp_mode = 3;
201
202   m_decomp_buffer_rdoffset = 0;
203   m_decomp_buffer_wroffset = 0;
204   m_decomp_buffer_length   = 0;
205}
206
207void SPC7110Decomp::init(running_machine &machine, UINT8 *ROM, UINT32 mode, UINT32 offset, UINT32 index)
208{
209   m_decomp_mode = mode;
210   m_decomp_offset = offset;
211
212   m_decomp_buffer_rdoffset = 0;
213   m_decomp_buffer_wroffset = 0;
214   m_decomp_buffer_length   = 0;
215
216   //reset context states
217   for (int i = 0; i < 32; i++)
218   {
219      m_context[i].index  = 0;
220      m_context[i].invert = 0;
221   }
222
223   switch (m_decomp_mode)
224   {
225      case 0: mode0(1, ROM); break;
226      case 1: mode1(1, ROM); break;
227      case 2: mode2(1, ROM); break;
228   }
229
230   //decompress up to requested output data index
231   while (index--)
232   {
233      read(ROM);
234   }
235}
236
237UINT8 SPC7110Decomp::read(UINT8 *ROM)
238{
239   UINT8 data;
240
241   if (m_decomp_buffer_length == 0)
242   {
243      //decompress at least (SPC7110_DECOMP_BUFFER_SIZE / 2) bytes to the buffer
244      switch (m_decomp_mode)
245      {
246         case 0:
247            mode0(0, ROM);
248            break;
249
250         case 1:
251            mode1(0, ROM);
252            break;
253
254         case 2:
255            mode2(0, ROM);
256            break;
257
258         default:
259            return 0x00;
260      }
261   }
262
263   data = m_decomp_buffer[m_decomp_buffer_rdoffset++];
264   m_decomp_buffer_rdoffset &= SPC7110_DECOMP_BUFFER_SIZE - 1;
265   m_decomp_buffer_length--;
266   return data;
267}
268
269void SPC7110Decomp::write(UINT8 data)
270{
271   m_decomp_buffer[m_decomp_buffer_wroffset++] = data;
272   m_decomp_buffer_wroffset &= SPC7110_DECOMP_BUFFER_SIZE - 1;
273   m_decomp_buffer_length++;
274}
275
276UINT8 SPC7110Decomp::dataread(UINT8 *ROM)
277{
278   UINT32 size = m_rom_size - 0x100000;
279   while (m_decomp_offset >= size)
280   {
281      m_decomp_offset -= size;
282   }
283   return ROM[0x100000 + m_decomp_offset++];
284}
285
286void SPC7110Decomp::mode0(UINT8 init, UINT8 *ROM)
287{
288   static UINT8 val, in, span;
289   static INT32 out, inverts, lps, in_count;
290
291   if (init == 1)
292   {
293      out = inverts = lps = 0;
294      span = 0xff;
295      val = dataread(ROM);
296      in = dataread(ROM);
297      in_count = 8;
298      return;
299   }
300
301   while (m_decomp_buffer_length < (SPC7110_DECOMP_BUFFER_SIZE >> 1))
302   {
303      for (int bit = 0; bit < 8; bit++)
304      {
305         //get context
306         UINT8 mask = (1 << (bit & 3)) - 1;
307         UINT8 con = mask + ((inverts & mask) ^ (lps & mask));
308         UINT32 prob, mps, flag_lps;
309         UINT32 shift = 0;
310         if (bit > 3)
311         {
312            con += 15;
313         }
314
315         //get prob and mps
316         prob = probability(con);
317         mps = (((out >> 15) & 1) ^ m_context[con].invert);
318
319         //get bit
320         if (val <= span - prob) //mps
321         {
322            span = span - prob;
323            out = (out << 1) + mps;
324            flag_lps = 0;
325         }
326         else //lps
327         {
328            val = val - (span - (prob - 1));
329            span = prob - 1;
330            out = (out << 1) + 1 - mps;
331            flag_lps = 1;
332         }
333
334         //renormalize
335         while (span < 0x7f)
336         {
337            shift++;
338
339            span = (span << 1) + 1;
340            val = (val << 1) + (in >> 7);
341
342            in <<= 1;
343            if (--in_count == 0)
344            {
345               in = dataread(ROM);
346               in_count = 8;
347            }
348         }
349
350         //update processing info
351         lps = (lps << 1) + flag_lps;
352         inverts = (inverts << 1) + m_context[con].invert;
353
354         //update context state
355         if (flag_lps & toggle_invert(con))
356         {
357            m_context[con].invert ^= 1;
358         }
359         if (flag_lps)
360         {
361            m_context[con].index = next_lps(con);
362         }
363         else if (shift)
364         {
365            m_context[con].index = next_mps(con);
366         }
367      }
368
369      //save byte
370      write(out);
371   }
372}
373
374void SPC7110Decomp::mode1(UINT8 init, UINT8 *ROM)
375{
376   static INT32 pixelorder[4], realorder[4];
377   static UINT8 in, val, span;
378   static INT32 out, inverts, lps, in_count;
379
380   if (init == 1)
381   {
382      for (int i = 0; i < 4; i++)
383      {
384         pixelorder[i] = i;
385      }
386      out = inverts = lps = 0;
387      span = 0xff;
388      val = dataread(ROM);
389      in = dataread(ROM);
390      in_count = 8;
391      return;
392   }
393
394   while (m_decomp_buffer_length < (SPC7110_DECOMP_BUFFER_SIZE >> 1))
395   {
396      UINT16 data;
397      for (int pixel = 0; pixel < 8; pixel++)
398      {
399         //get first symbol context
400         UINT32 a = ((out >> (1 * 2)) & 3);
401         UINT32 b = ((out >> (7 * 2)) & 3);
402         UINT32 c = ((out >> (8 * 2)) & 3);
403         UINT32 con = (a == b) ? (b != c) : (b == c) ? 2 : 4 - (a == c);
404
405         //update pixel order
406         UINT32 m, n;
407         for (m = 0; m < 4; m++)
408         {
409            if (pixelorder[m] == a)
410            {
411               break;
412            }
413         }
414         for (n = m; n > 0; n--)
415         {
416            pixelorder[n] = pixelorder[n - 1];
417         }
418         pixelorder[0] = a;
419
420         //calculate the real pixel order
421         for (m = 0; m < 4; m++)
422         {
423            realorder[m] = pixelorder[m];
424         }
425
426         //rotate reference pixel c value to top
427         for (m = 0; m < 4; m++)
428         {
429            if (realorder[m] == c)
430            {
431               break;
432            }
433         }
434         for (n = m; n > 0; n--)
435         {
436            realorder[n] = realorder[n - 1];
437         }
438         realorder[0] = c;
439
440         //rotate reference pixel b value to top
441         for (m = 0; m < 4; m++)
442         {
443            if (realorder[m] == b)
444            {
445               break;
446            }
447         }
448         for (n = m; n > 0; n--)
449         {
450            realorder[n] = realorder[n - 1];
451         }
452         realorder[0] = b;
453
454         //rotate reference pixel a value to top
455         for (m = 0; m < 4; m++)
456         {
457            if (realorder[m] == a)
458            {
459               break;
460            }
461         }
462         for (n = m; n > 0; n--)
463         {
464            realorder[n] = realorder[n - 1];
465         }
466         realorder[0] = a;
467
468         //get 2 symbols
469         for (int bit = 0; bit < 2; bit++)
470         {
471            //get prob
472            UINT32 prob = probability(con);
473            UINT32 shift = 0;
474
475            //get symbol
476            UINT32 flag_lps;
477            if (val <= span - prob) //mps
478            {
479               span = span - prob;
480               flag_lps = 0;
481            }
482            else //lps
483            {
484               val = val - (span - (prob - 1));
485               span = prob - 1;
486               flag_lps = 1;
487            }
488
489            //renormalize
490            while (span < 0x7f)
491            {
492               shift++;
493
494               span = (span << 1) + 1;
495               val = (val << 1) + (in >> 7);
496
497               in <<= 1;
498               if (--in_count == 0)
499               {
500                  in = dataread(ROM);
501                  in_count = 8;
502               }
503            }
504
505            //update processing info
506            lps = (lps << 1) + flag_lps;
507            inverts = (inverts << 1) + m_context[con].invert;
508
509            //update context state
510            if (flag_lps & toggle_invert(con))
511            {
512               m_context[con].invert ^= 1;
513            }
514            if (flag_lps)
515            {
516               m_context[con].index = next_lps(con);
517            }
518            else if (shift)
519            {
520               m_context[con].index = next_mps(con);
521            }
522
523            //get next context
524            con = 5 + (con << 1) + ((lps ^ inverts) & 1);
525         }
526
527         //get pixel
528         b = realorder[(lps ^ inverts) & 3];
529         out = (out << 2) + b;
530      }
531
532      //turn pixel data into bitplanes
533      data = morton_2x8(out);
534      write(data >> 8);
535      write(data >> 0);
536   }
537}
538
539void SPC7110Decomp::mode2(UINT8 init, UINT8 *ROM)
540{
541   static INT32 pixelorder[16], realorder[16];
542   static UINT8 bitplanebuffer[16], buffer_index;
543   static UINT8 in, val, span;
544   static INT32 out0, out1, inverts, lps, in_count;
545
546   if (init == 1)
547   {
548      for (int i = 0; i < 16; i++)
549      {
550         pixelorder[i] = i;
551      }
552      buffer_index = 0;
553      out0 = out1 = inverts = lps = 0;
554      span = 0xff;
555      val = dataread(ROM);
556      in = dataread(ROM);
557      in_count = 8;
558      return;
559   }
560
561   while (m_decomp_buffer_length < (SPC7110_DECOMP_BUFFER_SIZE >> 1))
562   {
563      UINT32 data;
564      for (int pixel = 0; pixel < 8; pixel++)
565      {
566         //get first symbol context
567         UINT32 a = ((out0 >> (0 * 4)) & 15);
568         UINT32 b = ((out0 >> (7 * 4)) & 15);
569         UINT32 c = ((out1 >> (0 * 4)) & 15);
570         UINT32 con = 0;
571         UINT32 refcon = (a == b) ? (b != c) : (b == c) ? 2 : 4 - (a == c);
572
573         //update pixel order
574         UINT32 m, n;
575         for (m = 0; m < 16; m++)
576         {
577            if (pixelorder[m] == a)
578            {
579               break;
580            }
581         }
582         for (n = m; n >  0; n--)
583         {
584            pixelorder[n] = pixelorder[n - 1];
585         }
586         pixelorder[0] = a;
587
588         //calculate the real pixel order
589         for (m = 0; m < 16; m++)
590         {
591            realorder[m] = pixelorder[m];
592         }
593
594         //rotate reference pixel c value to top
595         for (m = 0; m < 16; m++)
596         {
597            if (realorder[m] == c)
598            {
599               break;
600            }
601         }
602         for (n = m; n >  0; n--)
603         {
604            realorder[n] = realorder[n - 1];
605         }
606         realorder[0] = c;
607
608         //rotate reference pixel b value to top
609         for (m = 0; m < 16; m++)
610         {
611            if (realorder[m] == b)
612            {
613               break;
614            }
615         }
616         for (n = m; n >  0; n--)
617         {
618            realorder[n] = realorder[n - 1];
619         }
620         realorder[0] = b;
621
622         //rotate reference pixel a value to top
623         for (m = 0; m < 16; m++)
624         {
625            if (realorder[m] == a)
626            {
627               break;
628            }
629         }
630         for (n = m; n >  0; n--)
631         {
632            realorder[n] = realorder[n - 1];
633         }
634         realorder[0] = a;
635
636         //get 4 symbols
637         for (int bit = 0; bit < 4; bit++)
638         {
639            UINT32 invertbit, shift;
640
641            //get prob
642            UINT32 prob = probability(con);
643
644            //get symbol
645            UINT32 flag_lps;
646            if (val <= span - prob) //mps
647            {
648               span = span - prob;
649               flag_lps = 0;
650            }
651            else //lps
652            {
653               val = val - (span - (prob - 1));
654               span = prob - 1;
655               flag_lps = 1;
656            }
657
658            //renormalize
659            shift = 0;
660            while (span < 0x7f)
661            {
662               shift++;
663
664               span = (span << 1) + 1;
665               val = (val << 1) + (in >> 7);
666
667               in <<= 1;
668               if (--in_count == 0)
669               {
670                  in = dataread(ROM);
671                  in_count = 8;
672               }
673            }
674
675            //update processing info
676            lps = (lps << 1) + flag_lps;
677            invertbit = m_context[con].invert;
678            inverts = (inverts << 1) + invertbit;
679
680            //update context state
681            if (flag_lps & toggle_invert(con))
682            {
683               m_context[con].invert ^= 1;
684            }
685            if (flag_lps)
686            {
687               m_context[con].index = next_lps(con);
688            }
689            else if (shift)
690            {
691               m_context[con].index = next_mps(con);
692            }
693
694            //get next context
695            con = spc7110_mode2_context_table[con][flag_lps ^ invertbit] + (con == 1 ? refcon : 0);
696         }
697
698         //get pixel
699         b = realorder[(lps ^ inverts) & 0x0f];
700         out1 = (out1 << 4) + ((out0 >> 28) & 0x0f);
701         out0 = (out0 << 4) + b;
702      }
703
704      //convert pixel data into bitplanes
705      data = morton_4x8(out0);
706      write(data >> 24);
707      write(data >> 16);
708      bitplanebuffer[buffer_index++] = data >> 8;
709      bitplanebuffer[buffer_index++] = data >> 0;
710
711      if (buffer_index == 16)
712      {
713         for (int i = 0; i < 16; i++)
714         {
715            write(bitplanebuffer[i]);
716         }
717         buffer_index = 0;
718      }
719   }
720}
721
722UINT8 SPC7110Decomp::probability(UINT32 n)
723{
724   return spc7110_evolution_table[m_context[n].index][0];
725}
726
727UINT8 SPC7110Decomp::next_lps(UINT32 n)
728{
729   return spc7110_evolution_table[m_context[n].index][1];
730}
731
732UINT8 SPC7110Decomp::next_mps(UINT32 n)
733{
734   return spc7110_evolution_table[m_context[n].index][2];
735}
736
737UINT8 SPC7110Decomp::toggle_invert(UINT32 n)
738{
739   return spc7110_evolution_table[m_context[n].index][3];
740}
741
742UINT32 SPC7110Decomp::morton_2x8(UINT32 data)
743{
744   //reverse morton lookup: de-interleave two 8-bit values
745   //15, 13, 11,  9,  7,  5,  3,  1 -> 15- 8
746   //14, 12, 10,  8,  6,  4,  2,  0 ->  7- 0
747   return m_morton16[0][(data >>  0) & 255] + m_morton16[1][(data >>  8) & 255];
748}
749
750UINT32 SPC7110Decomp::morton_4x8(UINT32 data)
751{
752   //reverse morton lookup: de-interleave four 8-bit values
753   //31, 27, 23, 19, 15, 11,  7,  3 -> 31-24
754   //30, 26, 22, 18, 14, 10,  6,  2 -> 23-16
755   //29, 25, 21, 17, 13,  9,  5,  1 -> 15- 8
756   //28, 24, 20, 16, 12,  8,  4,  0 ->  7- 0
757   return m_morton32[0][(data >>  0) & 255] + m_morton32[1][(data >>  8) & 255]
758      + m_morton32[2][(data >> 16) & 255] + m_morton32[3][(data >> 24) & 255];
759}
760
761static void spc7110_update_time(running_machine &machine, UINT8 offset);
762
763enum RTC_State
764{
765   RTCS_Inactive,
766   RTCS_ModeSelect,
767   RTCS_IndexSelect,
768   RTCS_Write
769};
770
771enum RTC_Mode
772{
773   RTCM_Linear = 0x03,
774   RTCM_Indexed = 0x0c
775};
776
777static const UINT32 spc7110_months[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
778
779struct snes_spc7110_t
780{
781   //==================
782   //decompression unit
783   //==================
784   UINT8 r4801;        // compression table low
785   UINT8 r4802;        // compression table high
786   UINT8 r4803;        // compression table bank
787   UINT8 r4804;        // compression table index
788   UINT8 r4805;        // decompression buffer index low
789   UINT8 r4806;        // decompression buffer index high
790   UINT8 r4807;        // ???
791   UINT8 r4808;        // ???
792   UINT8 r4809;        // compression length low
793   UINT8 r480a;        // compression length high
794   UINT8 r480b;        // decompression control register
795   UINT8 r480c;        // decompression status
796
797   SPC7110Decomp* decomp;
798
799   UINT8 r4811;        // data pointer low
800   UINT8 r4812;        // data pointer high
801   UINT8 r4813;        // data pointer bank
802   UINT8 r4814;        // data adjust low
803   UINT8 r4815;        // data adjust high
804   UINT8 r4816;        // data increment low
805   UINT8 r4817;        // data increment high
806   UINT8 r4818;        // data port control register
807
808   UINT8 r481x;
809
810   UINT8 r4814_latch;
811   UINT8 r4815_latch;
812
813   //=========
814   //math unit
815   //=========
816   UINT8 r4820;        // 16-bit multiplicand B0, 32-bit dividend B0
817   UINT8 r4821;        // 16-bit multiplicand B1, 32-bit dividend B1
818   UINT8 r4822;        // 32-bit dividend B2
819   UINT8 r4823;        // 32-bit dividend B3
820   UINT8 r4824;        // 16-bit multiplier B0
821   UINT8 r4825;        // 16-bit multiplier B1
822   UINT8 r4826;        // 16-bit divisor B0
823   UINT8 r4827;        // 16-bit divisor B1
824   UINT8 r4828;        // 32-bit product B0, 32-bit quotient B0
825   UINT8 r4829;        // 32-bit product B1, 32-bit quotient B1
826   UINT8 r482a;        // 32-bit product B2, 32-bit quotient B2
827   UINT8 r482b;        // 32-bit product B3, 32-bit quotient B3
828   UINT8 r482c;        // 16-bit remainder B0
829   UINT8 r482d;        // 16-bit remainder B1
830   UINT8 r482e;        // math control register
831   UINT8 r482f;        // math status
832
833   //===================
834   //memory mapping unit
835   //===================
836   UINT8 r4830;        // SRAM write enable
837   UINT8 r4831;        // $[d0-df]:[0000-ffff] mapping
838   UINT8 r4832;        // $[e0-ef]:[0000-ffff] mapping
839   UINT8 r4833;        // $[f0-ff]:[0000-ffff] mapping
840   UINT8 r4834;        // ???
841
842   UINT32 dx_offset;
843   UINT32 ex_offset;
844   UINT32 fx_offset;
845
846   //====================
847   //real-time clock unit
848   //====================
849   UINT8 r4840;        // RTC latch
850   UINT8 r4841;        // RTC index/data port
851   UINT8 r4842;        // RTC status
852
853   UINT32 rtc_state;
854   UINT32 rtc_mode;
855   UINT32 rtc_index;
856
857   UINT64 rtc_offset;
858
859   UINT8 rtc_ram[16];  // 0-12 secs, min, hrs, etc.; 13-14-15 control registers
860
861   UINT32 size;
862};
863
864static snes_spc7110_t snes_spc7110;
865
866void spc7110_init(running_machine& machine)
867{
868   snes_state *state = machine.driver_data<snes_state>();
869
870   snes_spc7110.r4801 = 0x00;
871   snes_spc7110.r4802 = 0x00;
872   snes_spc7110.r4803 = 0x00;
873   snes_spc7110.r4804 = 0x00;
874   snes_spc7110.r4805 = 0x00;
875   snes_spc7110.r4806 = 0x00;
876   snes_spc7110.r4807 = 0x00;
877   snes_spc7110.r4808 = 0x00;
878   snes_spc7110.r4809 = 0x00;
879   snes_spc7110.r480a = 0x00;
880   snes_spc7110.r480b = 0x00;
881   snes_spc7110.r480c = 0x00;
882
883   snes_spc7110.r4811 = 0x00;
884   snes_spc7110.r4812 = 0x00;
885   snes_spc7110.r4813 = 0x00;
886   snes_spc7110.r4814 = 0x00;
887   snes_spc7110.r4815 = 0x00;
888   snes_spc7110.r4816 = 0x00;
889   snes_spc7110.r4817 = 0x00;
890   snes_spc7110.r4818 = 0x00;
891
892   snes_spc7110.r481x = 0x00;
893   snes_spc7110.r4814_latch = 0;
894   snes_spc7110.r4815_latch = 0;
895
896   snes_spc7110.r4820 = 0x00;
897   snes_spc7110.r4821 = 0x00;
898   snes_spc7110.r4822 = 0x00;
899   snes_spc7110.r4823 = 0x00;
900   snes_spc7110.r4824 = 0x00;
901   snes_spc7110.r4825 = 0x00;
902   snes_spc7110.r4826 = 0x00;
903   snes_spc7110.r4827 = 0x00;
904   snes_spc7110.r4828 = 0x00;
905   snes_spc7110.r4829 = 0x00;
906   snes_spc7110.r482a = 0x00;
907   snes_spc7110.r482b = 0x00;
908   snes_spc7110.r482c = 0x00;
909   snes_spc7110.r482d = 0x00;
910   snes_spc7110.r482e = 0x00;
911   snes_spc7110.r482f = 0x00;
912
913   snes_spc7110.r4830 = 0x00;
914   spc7110_mmio_write(machine, 0x4831, 0);
915   spc7110_mmio_write(machine, 0x4832, 1);
916   spc7110_mmio_write(machine, 0x4833, 2);
917   snes_spc7110.r4834 = 0x00;
918
919   snes_spc7110.r4840 = 0x00;
920   snes_spc7110.r4841 = 0x00;
921   snes_spc7110.r4842 = 0x00;
922
923   snes_spc7110.size = state->m_cart_size;
924
925   snes_spc7110.decomp = auto_alloc(machine, SPC7110Decomp(machine, snes_spc7110.size));
926}
927
928void spc7110rtc_init(running_machine& machine)
929{
930   spc7110_init(machine);
931
932   snes_spc7110.rtc_state = RTCS_Inactive;
933   snes_spc7110.rtc_mode  = RTCM_Linear;
934   snes_spc7110.rtc_index = 0;
935
936   snes_spc7110.rtc_offset = 0;
937
938   spc7110_update_time(machine, 0);
939}
940
941static UINT32 spc7110_datarom_addr(UINT32 addr)
942{
943   UINT32 size = snes_spc7110.size - 0x100000;
944   while (addr >= size)
945   {
946      addr -= size;
947   }
948   return addr + 0x100000;
949}
950
951static UINT32 spc7110_data_pointer(void)
952{
953   return snes_spc7110.r4811 + (snes_spc7110.r4812 << 8) + (snes_spc7110.r4813 << 16);
954}
955
956static UINT32 spc7110_data_adjust(void)
957{
958   return snes_spc7110.r4814 + (snes_spc7110.r4815 << 8);
959}
960
961static UINT32 spc7110_data_increment(void)
962{
963   return snes_spc7110.r4816 + (snes_spc7110.r4817 << 8);
964}
965
966static void spc7110_set_data_pointer(UINT32 addr)
967{
968   snes_spc7110.r4811 = addr;
969   snes_spc7110.r4812 = addr >> 8;
970   snes_spc7110.r4813 = addr >> 16;
971}
972
973static void spc7110_set_data_adjust(UINT32 addr)
974{
975   snes_spc7110.r4814 = addr;
976   snes_spc7110.r4815 = addr >> 8;
977}
978
979// FIXME: SPC7110 RTC is capable of rounding/adding/zero-ing seconds, so
980// we should probably keep track internally of the time rather than updating
981// to the system time at each call with a "offset" tracking as we do now...
982// (and indeed current code fails to pass Tengai Makyou Zero tests)
983static void spc7110_update_time(running_machine &machine, UINT8 offset)
984{
985   system_time curtime, *systime = &curtime;
986   machine.current_datetime(curtime);
987   int update = 1;
988
989   snes_spc7110.rtc_offset += offset;
990
991   // TEST: can we go beyond 24hrs of rounding?!? I doubt it will ever go beyond 3600, but I could be wrong...
992   assert(snes_spc7110.rtc_offset < 86400);
993
994   /* do not update if CR0 or CR2 timer disable flags are set */
995   if ((snes_spc7110.rtc_ram[13] & 0x01) || (snes_spc7110.rtc_ram[15] & 0x03))
996      update = 0;
997
998   if (update)
999   {
1000      /* update time with offset, assuming offset < 3600s */
1001      UINT8 second = systime->local_time.second;
1002      UINT8 minute = systime->local_time.minute;
1003      UINT8 hour = systime->local_time.hour;
1004      UINT8 mday = systime->local_time.mday;
1005
1006      while (snes_spc7110.rtc_offset >= 3600)
1007      {
1008         snes_spc7110.rtc_offset -= 3600;
1009         hour++;
1010
1011         if (hour == 24)
1012         {
1013            mday++;
1014            hour = 0;
1015         }
1016      }
1017
1018      while (snes_spc7110.rtc_offset >= 60)
1019      {
1020         snes_spc7110.rtc_offset -= 60;
1021         minute++;
1022
1023         if (minute == 60)
1024         {
1025            hour++;
1026            minute = 0;
1027         }
1028      }
1029
1030      while (snes_spc7110.rtc_offset)
1031      {
1032         snes_spc7110.rtc_offset -= 1;
1033         second++;
1034
1035         if (second == 60)
1036         {
1037            minute++;
1038            second = 0;
1039         }
1040      }
1041
1042      snes_spc7110.rtc_ram[0] = second % 10;
1043      snes_spc7110.rtc_ram[1] = second / 10;
1044      snes_spc7110.rtc_ram[2] = minute % 10;
1045      snes_spc7110.rtc_ram[3] = minute / 10;
1046      snes_spc7110.rtc_ram[4] = hour % 10;
1047      snes_spc7110.rtc_ram[5] = hour / 10;
1048      snes_spc7110.rtc_ram[6] = mday % 10;
1049      snes_spc7110.rtc_ram[7] = mday / 10;
1050      snes_spc7110.rtc_ram[8] = systime->local_time.month % 10;
1051      snes_spc7110.rtc_ram[9] = systime->local_time.month / 10;
1052      snes_spc7110.rtc_ram[8] = systime->local_time.month;
1053      snes_spc7110.rtc_ram[10] = (systime->local_time.year - 1900) % 10;
1054      snes_spc7110.rtc_ram[11] = ((systime->local_time.year - 1900) / 10) % 10;
1055      snes_spc7110.rtc_ram[12] = systime->local_time.weekday % 7;
1056   }
1057}
1058
1059UINT8 spc7110_mmio_read(address_space &space, UINT32 addr)
1060{
1061   running_machine &machine = space.machine();
1062   UINT8 *ROM = machine.root_device().memregion("cart")->base();
1063
1064   addr &= 0xffff;
1065
1066   switch(addr)
1067   {
1068   //==================
1069   //decompression unit
1070   //==================
1071
1072   case 0x4800:
1073      {
1074         UINT16 counter = (snes_spc7110.r4809 + (snes_spc7110.r480a << 8));
1075         counter--;
1076         snes_spc7110.r4809 = counter;
1077         snes_spc7110.r480a = counter >> 8;
1078         return snes_spc7110.decomp->read(ROM);
1079      }
1080   case 0x4801: return snes_spc7110.r4801;
1081   case 0x4802: return snes_spc7110.r4802;
1082   case 0x4803: return snes_spc7110.r4803;
1083   case 0x4804: return snes_spc7110.r4804;
1084   case 0x4805: return snes_spc7110.r4805;
1085   case 0x4806: return snes_spc7110.r4806;
1086   case 0x4807: return snes_spc7110.r4807;
1087   case 0x4808: return snes_spc7110.r4808;
1088   case 0x4809: return snes_spc7110.r4809;
1089   case 0x480a: return snes_spc7110.r480a;
1090   case 0x480b: return snes_spc7110.r480b;
1091   case 0x480c:
1092      {
1093         UINT8 status = snes_spc7110.r480c;
1094         snes_spc7110.r480c &= 0x7f;
1095         return status;
1096      }
1097
1098   //==============
1099   //data port unit
1100   //==============
1101
1102   case 0x4810:
1103      {
1104         UINT8 data;
1105         UINT32 address, adjust, adjustaddr;
1106
1107         if (snes_spc7110.r481x != 0x07) return 0x00;
1108
1109         address = spc7110_data_pointer();
1110         adjust = spc7110_data_adjust();
1111         if (snes_spc7110.r4818 & 8)
1112         {
1113            adjust = (INT16)adjust;  //16-bit sign extend
1114         }
1115
1116         adjustaddr = address;
1117         if (snes_spc7110.r4818 & 2)
1118         {
1119            adjustaddr += adjust;
1120            spc7110_set_data_adjust(adjust + 1);
1121         }
1122
1123         data = ROM[spc7110_datarom_addr(adjustaddr)];
1124         if (!(snes_spc7110.r4818 & 2))
1125         {
1126            UINT32 increment = (snes_spc7110.r4818 & 1) ? spc7110_data_increment() : 1;
1127            if (snes_spc7110.r4818 & 4)
1128            {
1129               increment = (INT16)increment;  //16-bit sign extend
1130            }
1131
1132            if ((snes_spc7110.r4818 & 16) == 0)
1133            {
1134               spc7110_set_data_pointer(address + increment);
1135            }
1136            else
1137            {
1138               spc7110_set_data_adjust(adjust + increment);
1139            }
1140         }
1141
1142         return data;
1143      }
1144   case 0x4811: return snes_spc7110.r4811;
1145   case 0x4812: return snes_spc7110.r4812;
1146   case 0x4813: return snes_spc7110.r4813;
1147   case 0x4814: return snes_spc7110.r4814;
1148   case 0x4815: return snes_spc7110.r4815;
1149   case 0x4816: return snes_spc7110.r4816;
1150   case 0x4817: return snes_spc7110.r4817;
1151   case 0x4818: return snes_spc7110.r4818;
1152   case 0x481a:
1153      {
1154         UINT8 data;
1155         UINT32 address, adjust;
1156         if (snes_spc7110.r481x != 0x07)
1157         {
1158            return 0x00;
1159         }
1160
1161         address = spc7110_data_pointer();
1162         adjust = spc7110_data_adjust();
1163         if (snes_spc7110.r4818 & 8)
1164         {
1165            adjust = (INT16)adjust;  //16-bit sign extend
1166         }
1167
1168         data = ROM[spc7110_datarom_addr(address + adjust)];
1169         if ((snes_spc7110.r4818 & 0x60) == 0x60)
1170         {
1171            if ((snes_spc7110.r4818 & 16) == 0)
1172            {
1173               spc7110_set_data_pointer(address + adjust);
1174            }
1175            else
1176            {
1177               spc7110_set_data_adjust(adjust + adjust);
1178            }
1179         }
1180
1181         return data;
1182      }
1183
1184   //=========
1185   //math unit
1186   //=========
1187
1188   case 0x4820: return snes_spc7110.r4820;
1189   case 0x4821: return snes_spc7110.r4821;
1190   case 0x4822: return snes_spc7110.r4822;
1191   case 0x4823: return snes_spc7110.r4823;
1192   case 0x4824: return snes_spc7110.r4824;
1193   case 0x4825: return snes_spc7110.r4825;
1194   case 0x4826: return snes_spc7110.r4826;
1195   case 0x4827: return snes_spc7110.r4827;
1196   case 0x4828: return snes_spc7110.r4828;
1197   case 0x4829: return snes_spc7110.r4829;
1198   case 0x482a: return snes_spc7110.r482a;
1199   case 0x482b: return snes_spc7110.r482b;
1200   case 0x482c: return snes_spc7110.r482c;
1201   case 0x482d: return snes_spc7110.r482d;
1202   case 0x482e: return snes_spc7110.r482e;
1203   case 0x482f:
1204      {
1205         UINT8 status = snes_spc7110.r482f;
1206         snes_spc7110.r482f &= 0x7f;
1207         return status;
1208      }
1209
1210   //===================
1211   //memory mapping unit
1212   //===================
1213
1214   case 0x4830: return snes_spc7110.r4830;
1215   case 0x4831: return snes_spc7110.r4831;
1216   case 0x4832: return snes_spc7110.r4832;
1217   case 0x4833: return snes_spc7110.r4833;
1218   case 0x4834: return snes_spc7110.r4834;
1219
1220   //====================
1221   //real-time clock unit
1222   //====================
1223   case 0x4840: return snes_spc7110.r4840;
1224   case 0x4841:
1225      {
1226         UINT8 data = 0;
1227         if (snes_spc7110.rtc_state == RTCS_Inactive || snes_spc7110.rtc_state == RTCS_ModeSelect)
1228            return 0x00;
1229
1230         snes_spc7110.r4842 = 0x80;
1231         data = snes_spc7110.rtc_ram[snes_spc7110.rtc_index];
1232         snes_spc7110.rtc_index = (snes_spc7110.rtc_index + 1) & 15;
1233         return data;
1234      }
1235   case 0x4842:
1236      {
1237         UINT8 status = snes_spc7110.r4842;
1238         snes_spc7110.r4842 &= 0x7f;
1239         return status;
1240      }
1241   }
1242
1243   return snes_open_bus_r(space, 0);
1244}
1245
1246void spc7110_mmio_write(running_machine &machine, UINT32 addr, UINT8 data)
1247{
1248   UINT8 *ROM = machine.root_device().memregion("cart")->base();
1249
1250   addr &= 0xffff;
1251
1252   switch(addr)
1253   {
1254   //==================
1255   //decompression unit
1256   //==================
1257
1258   case 0x4801: snes_spc7110.r4801 = data; break;
1259   case 0x4802: snes_spc7110.r4802 = data; break;
1260   case 0x4803: snes_spc7110.r4803 = data; break;
1261   case 0x4804: snes_spc7110.r4804 = data; break;
1262   case 0x4805: snes_spc7110.r4805 = data; break;
1263   case 0x4806:
1264      {
1265         UINT32 table, index, address, mode, offset;
1266         snes_spc7110.r4806 = data;
1267
1268         table   = (snes_spc7110.r4801 + (snes_spc7110.r4802 << 8) + (snes_spc7110.r4803 << 16));
1269         index   = (snes_spc7110.r4804 << 2);
1270         //length  = (snes_spc7110.r4809 + (snes_spc7110.r480a << 8));
1271         address = spc7110_datarom_addr(table + index);
1272         mode    = (ROM[address + 0]);
1273         offset  = (ROM[address + 1] << 16)
1274               + (ROM[address + 2] <<  8)
1275               + (ROM[address + 3] <<  0);
1276
1277         snes_spc7110.decomp->init(machine, ROM, mode, offset, (snes_spc7110.r4805 + (snes_spc7110.r4806 << 8)) << mode);
1278         snes_spc7110.r480c = 0x80;
1279      }
1280      break;
1281
1282   case 0x4807: snes_spc7110.r4807 = data; break;
1283   case 0x4808: snes_spc7110.r4808 = data; break;
1284   case 0x4809: snes_spc7110.r4809 = data; break;
1285   case 0x480a: snes_spc7110.r480a = data; break;
1286   case 0x480b: snes_spc7110.r480b = data; break;
1287
1288   //==============
1289   //data port unit
1290   //==============
1291
1292   case 0x4811: snes_spc7110.r4811 = data; snes_spc7110.r481x |= 0x01; break;
1293   case 0x4812: snes_spc7110.r4812 = data; snes_spc7110.r481x |= 0x02; break;
1294   case 0x4813: snes_spc7110.r4813 = data; snes_spc7110.r481x |= 0x04; break;
1295   case 0x4814:
1296      {
1297         snes_spc7110.r4814 = data;
1298         snes_spc7110.r4814_latch = 1;
1299         if (!snes_spc7110.r4815_latch)
1300         {
1301            break;
1302         }
1303         if (!(snes_spc7110.r4818 & 2))
1304         {
1305            break;
1306         }
1307         if (snes_spc7110.r4818 & 0x10)
1308         {
1309            break;
1310         }
1311
1312         if ((snes_spc7110.r4818 & 0x60) == 0x20)
1313         {
1314            UINT32 increment = spc7110_data_adjust() & 0xff;
1315            if (snes_spc7110.r4818 & 8)
1316            {
1317               increment = (INT8)increment;  //8-bit sign extend
1318            }
1319            spc7110_set_data_pointer(spc7110_data_pointer() + increment);
1320         }
1321         else if ((snes_spc7110.r4818 & 0x60) == 0x40)
1322         {
1323            UINT32 increment = spc7110_data_adjust();
1324            if (snes_spc7110.r4818 & 8)
1325            {
1326               increment = (INT16)increment;  //16-bit sign extend
1327            }
1328            spc7110_set_data_pointer(spc7110_data_pointer() + increment);
1329         }
1330         break;
1331      }
1332
1333   case 0x4815:
1334      {
1335         snes_spc7110.r4815 = data;
1336         snes_spc7110.r4815_latch = 1;
1337         if (!snes_spc7110.r4814_latch)
1338         {
1339            break;
1340         }
1341         if (!(snes_spc7110.r4818 & 2))
1342         {
1343            break;
1344         }
1345         if (snes_spc7110.r4818 & 0x10)
1346         {
1347            break;
1348         }
1349
1350         if ((snes_spc7110.r4818 & 0x60) == 0x20)
1351         {
1352            UINT32 increment = spc7110_data_adjust() & 0xff;
1353            if (snes_spc7110.r4818 & 8)
1354            {
1355               increment = (INT8)increment;  //8-bit sign extend
1356            }
1357            spc7110_set_data_pointer(spc7110_data_pointer() + increment);
1358         }
1359         else if ((snes_spc7110.r4818 & 0x60) == 0x40)
1360         {
1361            UINT32 increment = spc7110_data_adjust();
1362            if (snes_spc7110.r4818 & 8)
1363            {
1364               increment = (INT16)increment;  //16-bit sign extend
1365            }
1366            spc7110_set_data_pointer(spc7110_data_pointer() + increment);
1367         }
1368         break;
1369      }
1370
1371   case 0x4816: snes_spc7110.r4816 = data; break;
1372   case 0x4817: snes_spc7110.r4817 = data; break;
1373   case 0x4818:
1374      {
1375            if (snes_spc7110.r481x != 0x07)
1376            break;
1377
1378            snes_spc7110.r4818 = data;
1379            snes_spc7110.r4814_latch = snes_spc7110.r4815_latch = 0;
1380            break;
1381         }
1382
1383   //=========
1384   //math unit
1385   //=========
1386
1387   case 0x4820: snes_spc7110.r4820 = data; break;
1388   case 0x4821: snes_spc7110.r4821 = data; break;
1389   case 0x4822: snes_spc7110.r4822 = data; break;
1390   case 0x4823: snes_spc7110.r4823 = data; break;
1391   case 0x4824: snes_spc7110.r4824 = data; break;
1392   case 0x4825:
1393      {
1394            snes_spc7110.r4825 = data;
1395
1396            if (snes_spc7110.r482e & 1)
1397         {
1398               //signed 16-bit x 16-bit multiplication
1399               INT16 r0 = (INT16)(snes_spc7110.r4824 + (snes_spc7110.r4825 << 8));
1400               INT16 r1 = (INT16)(snes_spc7110.r4820 + (snes_spc7110.r4821 << 8));
1401
1402               INT32 result = r0 * r1;
1403               snes_spc7110.r4828 = result;
1404               snes_spc7110.r4829 = result >> 8;
1405               snes_spc7110.r482a = result >> 16;
1406               snes_spc7110.r482b = result >> 24;
1407         }
1408         else
1409         {
1410               //unsigned 16-bit x 16-bit multiplication
1411               UINT16 r0 = (UINT16)(snes_spc7110.r4824 + (snes_spc7110.r4825 << 8));
1412               UINT16 r1 = (UINT16)(snes_spc7110.r4820 + (snes_spc7110.r4821 << 8));
1413
1414               UINT32 result = r0 * r1;
1415               snes_spc7110.r4828 = result;
1416               snes_spc7110.r4829 = result >> 8;
1417               snes_spc7110.r482a = result >> 16;
1418               snes_spc7110.r482b = result >> 24;
1419         }
1420
1421         snes_spc7110.r482f = 0x80;
1422         break;
1423      }
1424
1425   case 0x4826: snes_spc7110.r4826 = data; break;
1426   case 0x4827:
1427      {
1428         snes_spc7110.r4827 = data;
1429
1430         if (snes_spc7110.r482e & 1)
1431         {
1432            //signed 32-bit x 16-bit division
1433            INT32 dividend = (INT32)(snes_spc7110.r4820 + (snes_spc7110.r4821 << 8) + (snes_spc7110.r4822 << 16) + (snes_spc7110.r4823 << 24));
1434            INT16 divisor  = (INT16)(snes_spc7110.r4826 + (snes_spc7110.r4827 << 8));
1435
1436            INT32 quotient;
1437            INT16 remainder;
1438
1439            if (divisor)
1440            {
1441               quotient  = (INT32)(dividend / divisor);
1442               remainder = (INT32)(dividend % divisor);
1443            }
1444            else
1445            {
1446               //illegal division by zero
1447               quotient  = 0;
1448               remainder = dividend & 0xffff;
1449            }
1450
1451            snes_spc7110.r4828 = quotient;
1452            snes_spc7110.r4829 = quotient >> 8;
1453            snes_spc7110.r482a = quotient >> 16;
1454            snes_spc7110.r482b = quotient >> 24;
1455
1456            snes_spc7110.r482c = remainder;
1457            snes_spc7110.r482d = remainder >> 8;
1458         }
1459         else
1460         {
1461            //unsigned 32-bit x 16-bit division
1462            UINT32 dividend = (UINT32)(snes_spc7110.r4820 + (snes_spc7110.r4821 << 8) + (snes_spc7110.r4822 << 16) + (snes_spc7110.r4823 << 24));
1463            UINT16 divisor  = (UINT16)(snes_spc7110.r4826 + (snes_spc7110.r4827 << 8));
1464
1465            UINT32 quotient;
1466            UINT16 remainder;
1467
1468            if (divisor)
1469            {
1470               quotient  = (UINT32)(dividend / divisor);
1471               remainder = (UINT16)(dividend % divisor);
1472            }
1473            else
1474            {
1475               //illegal division by zero
1476               quotient  = 0;
1477               remainder = dividend & 0xffff;
1478            }
1479
1480            snes_spc7110.r4828 = quotient;
1481            snes_spc7110.r4829 = quotient >> 8;
1482            snes_spc7110.r482a = quotient >> 16;
1483            snes_spc7110.r482b = quotient >> 24;
1484
1485            snes_spc7110.r482c = remainder;
1486            snes_spc7110.r482d = remainder >> 8;
1487         }
1488
1489         snes_spc7110.r482f = 0x80;
1490         break;
1491      }
1492
1493   case 0x482e:
1494      {
1495         //reset math unit
1496         snes_spc7110.r4820 = snes_spc7110.r4821 = snes_spc7110.r4822 = snes_spc7110.r4823 = 0;
1497         snes_spc7110.r4824 = snes_spc7110.r4825 = snes_spc7110.r4826 = snes_spc7110.r4827 = 0;
1498         snes_spc7110.r4828 = snes_spc7110.r4829 = snes_spc7110.r482a = snes_spc7110.r482b = 0;
1499         snes_spc7110.r482c = snes_spc7110.r482d = 0;
1500
1501         snes_spc7110.r482e = data;
1502         break;
1503      }
1504
1505   //===================
1506   //memory mapping unit
1507   //===================
1508
1509   case 0x4830: snes_spc7110.r4830 = data; break;
1510
1511   case 0x4831:
1512      {
1513         snes_spc7110.r4831 = data;
1514         snes_spc7110.dx_offset = spc7110_datarom_addr(data * 0x100000);
1515         break;
1516      }
1517
1518   case 0x4832:
1519      {
1520         snes_spc7110.r4832 = data;
1521         snes_spc7110.ex_offset = spc7110_datarom_addr(data * 0x100000);
1522         break;
1523      }
1524
1525   case 0x4833:
1526      {
1527         snes_spc7110.r4833 = data;
1528         snes_spc7110.fx_offset = spc7110_datarom_addr(data * 0x100000);
1529         break;
1530      }
1531
1532   case 0x4834: snes_spc7110.r4834 = data; break;
1533
1534   //====================
1535   //real-time clock unit
1536   //====================
1537
1538   case 0x4840:
1539      {
1540         snes_spc7110.r4840 = data;
1541
1542         if (!(snes_spc7110.r4840 & 1))
1543         {
1544            //disable RTC
1545            snes_spc7110.rtc_state = RTCS_Inactive;
1546            spc7110_update_time(machine, 0);
1547         }
1548         else
1549         {
1550            //enable RTC
1551            snes_spc7110.r4842 = 0x80;
1552            snes_spc7110.rtc_state = RTCS_ModeSelect;
1553         }
1554      }
1555      break;
1556
1557   case 0x4841:
1558      {
1559         snes_spc7110.r4841 = data;
1560
1561         switch (snes_spc7110.rtc_state)
1562         {
1563         case RTCS_ModeSelect:
1564            if (data == RTCM_Linear || data == RTCM_Indexed)
1565            {
1566               snes_spc7110.r4842 = 0x80;
1567               snes_spc7110.rtc_state = RTCS_IndexSelect;
1568               snes_spc7110.rtc_mode = (RTC_Mode)data;
1569               snes_spc7110.rtc_index = 0;
1570            }
1571            break;
1572
1573         case RTCS_IndexSelect:
1574            snes_spc7110.r4842 = 0x80;
1575            snes_spc7110.rtc_index = data & 15;
1576            if (snes_spc7110.rtc_mode == RTCM_Linear)
1577               snes_spc7110.rtc_state = RTCS_Write;
1578            break;
1579
1580         case RTCS_Write:
1581            snes_spc7110.r4842 = 0x80;
1582
1583            //control register 0
1584            if (snes_spc7110.rtc_index == 13)
1585            {
1586               //increment second counter
1587               if (data & 2)
1588                  spc7110_update_time(machine, 1);
1589
1590               //round minute counter
1591               if (data & 8)
1592               {
1593                  spc7110_update_time(machine, 0);
1594
1595                  UINT8 second = snes_spc7110.rtc_ram[0] + snes_spc7110.rtc_ram[1] * 10;
1596                  //clear seconds
1597                  snes_spc7110.rtc_ram[0] = 0;
1598                  snes_spc7110.rtc_ram[1] = 0;
1599
1600                  if (second >= 30)
1601                     spc7110_update_time(machine, 60);
1602               }
1603            }
1604
1605            //control register 2
1606            if (snes_spc7110.rtc_index == 15)
1607            {
1608               //disable timer and clear second counter
1609               if ((data & 1) && !(snes_spc7110.rtc_ram[15]  & 1))
1610               {
1611                  spc7110_update_time(machine, 0);
1612
1613                  //clear seconds
1614                  snes_spc7110.rtc_ram[0] = 0;
1615                  snes_spc7110.rtc_ram[1] = 0;
1616               }
1617
1618               //disable timer
1619               if ((data & 2) && !(snes_spc7110.rtc_ram[15] & 2))
1620                  spc7110_update_time(machine, 0);
1621            }
1622
1623            snes_spc7110.rtc_ram[snes_spc7110.rtc_index] = data & 15;
1624            snes_spc7110.rtc_index = (snes_spc7110.rtc_index + 1) & 15;
1625            break;
1626         }
1627      }
1628      break;
1629   }
1630}
1631
1632UINT8 spc7110_bank7_read(address_space &space, UINT32 offset)
1633{
1634   UINT8 *ROM = space.machine().root_device().memregion("cart")->base();
1635   UINT32 addr = offset & 0x0fffff;
1636
1637   switch (offset & 0xf00000)
1638   {
1639   case 0x100000:
1640      return ROM[snes_spc7110.dx_offset + addr];
1641   case 0x200000:
1642      return ROM[snes_spc7110.ex_offset + addr];
1643   case 0x300000:
1644      return ROM[snes_spc7110.fx_offset + addr];
1645   default:
1646      break;
1647   }
1648   return snes_open_bus_r(space, 0);
1649}
Property changes on: trunk/src/mess/machine/snes7110.c
Added: svn:eol-style
   + native
Added: svn:mime-type
   + text/plain
trunk/src/mess/machine/cx4oam.c
r0r21590
1/***************************************************************************
2
3    cx4oam.c
4
5    Code based on original work by zsKnight, anomie and Nach.
6    This implementation is based on C++ "cx4*.cpp" by byuu
7    (up to date with source v 0.49).
8
9***************************************************************************/
10
11//Build OAM
12static void CX4_op00_00(running_machine &machine)
13{
14   INT32 i;
15
16   UINT32 oamptr = cx4.ram[0x626] << 2;
17   UINT16 globalx, globaly;
18   UINT32 oamptr2;
19   INT16 sprx, spry;
20   UINT8 sprname, sprattr;
21   UINT8 sprcount;
22   UINT8 offset;
23   UINT32 srcptr;
24
25   for(i = 0x1fd; i > oamptr && i >= 0; i -= 4)
26   {
27      //clear oam-to-be
28      if(i >= 0)
29      {
30         cx4.ram[i] = 0xe0;
31      }
32   }
33
34   globalx = CX4_readw(0x621);
35   globaly = CX4_readw(0x623);
36   oamptr2 = 0x200 + (cx4.ram[0x626] >> 2);
37
38   if(!cx4.ram[0x620])
39   {
40      return;
41   }
42
43   sprcount = 128 - cx4.ram[0x626];
44   offset = (cx4.ram[0x626] & 3) * 2;
45   srcptr = 0x220;
46
47   address_space &space = machine.device<cpu_device>("maincpu")->space(AS_PROGRAM);
48   for(i = cx4.ram[0x620]; i > 0 && sprcount > 0; i--, srcptr += 16)
49   {
50      UINT32 spraddr = CX4_readl(srcptr + 7);
51
52      sprx = CX4_readw(srcptr)     - globalx;
53      spry = CX4_readw(srcptr + 2) - globaly;
54      sprname = cx4.ram[srcptr + 5];
55      sprattr = cx4.ram[srcptr + 4] | cx4.ram[srcptr + 6];
56
57      if(space.read_byte(spraddr))
58      {
59         INT16 x, y;
60         INT32 sprcnt;
61         for(sprcnt = space.read_byte(spraddr++); sprcnt > 0 && sprcount > 0; sprcnt--, spraddr += 4)
62         {
63            x = (INT8)space.read_byte(spraddr + 1);
64            if(sprattr & 0x40)
65            {
66               x = -x - ((space.read_byte(spraddr) & 0x20) ? 16 : 8);
67            }
68            x += sprx;
69            if(x >= -16 && x <= 272)
70            {
71               y = (INT8)space.read_byte(spraddr + 2);
72               if(sprattr & 0x80)
73               {
74                  y = -y - ((space.read_byte(spraddr) & 0x20) ? 16 : 8);
75               }
76               y += spry;
77               if(y >= -16 && y <= 224)
78               {
79                  cx4.ram[oamptr    ] = (UINT8)x;
80                  cx4.ram[oamptr + 1] = (UINT8)y;
81                  cx4.ram[oamptr + 2] = sprname + space.read_byte(spraddr + 3);
82                  cx4.ram[oamptr + 3] = sprattr ^ (space.read_byte(spraddr) & 0xc0);
83                  cx4.ram[oamptr2] &= ~(3 << offset);
84                  if(x & 0x100)
85                  {
86                     cx4.ram[oamptr2] |= 1 << offset;
87                  }
88                  if(space.read_byte(spraddr) & 0x20)
89                  {
90                     cx4.ram[oamptr2] |= 2 << offset;
91                  }
92                  oamptr += 4;
93                  sprcount--;
94                  offset = (offset + 2) & 6;
95                  if(!offset)
96                  {
97                     oamptr2++;
98                  }
99               }
100            }
101         }
102      }
103      else if(sprcount > 0)
104      {
105         cx4.ram[oamptr    ] = (UINT8)sprx;
106         cx4.ram[oamptr + 1] = (UINT8)spry;
107         cx4.ram[oamptr + 2] = sprname;
108         cx4.ram[oamptr + 3] = sprattr;
109         cx4.ram[oamptr2] &= ~(3 << offset);
110         if(sprx & 0x100)
111         {
112            cx4.ram[oamptr2] |= 3 << offset;
113         }
114         else
115         {
116            cx4.ram[oamptr2] |= 2 << offset;
117         }
118         oamptr += 4;
119         sprcount--;
120         offset = (offset + 2) & 6;
121         if(!offset)
122         {
123            oamptr2++;
124         }
125      }
126   }
127}
128
129//Scale and Rotate
130static void CX4_op00_03(void)
131{
132   CX4_C4DoScaleRotate(0);
133}
134
135//Transform Lines
136static void CX4_op00_05(running_machine &machine)
137{
138   INT32 i;
139   UINT32 ptr = 0, ptr2 = 0;
140
141   cx4.C4WFX2Val = CX4_read(0x1f83);
142   cx4.C4WFY2Val = CX4_read(0x1f86);
143   cx4.C4WFDist  = CX4_read(0x1f89);
144   cx4.C4WFScale = CX4_read(0x1f8c);
145
146   //Transform Vertices
147   for(i = CX4_readw(0x1f80); i > 0; i--, ptr += 0x10)
148   {
149      cx4.C4WFXVal = CX4_readw(ptr + 1);
150      cx4.C4WFYVal = CX4_readw(ptr + 5);
151      cx4.C4WFZVal = CX4_readw(ptr + 9);
152      CX4_C4TransfWireFrame();
153
154      //Displace
155      CX4_writew(machine, ptr + 1, cx4.C4WFXVal + 0x80);
156      CX4_writew(machine, ptr + 5, cx4.C4WFYVal + 0x50);
157   }
158
159   CX4_writew(machine, 0x600,     23);
160   CX4_writew(machine, 0x602,     0x60);
161   CX4_writew(machine, 0x605,     0x40);
162   CX4_writew(machine, 0x600 + 8, 23);
163   CX4_writew(machine, 0x602 + 8, 0x60);
164   CX4_writew(machine, 0x605 + 8, 0x40);
165
166   ptr = 0xb02;
167
168   for(i = CX4_readw(0xb00); i > 0; i--, ptr += 2, ptr2 += 8)
169   {
170      cx4.C4WFXVal  = CX4_readw((CX4_read(ptr + 0) << 4) + 1);
171      cx4.C4WFYVal  = CX4_readw((CX4_read(ptr + 0) << 4) + 5);
172      cx4.C4WFX2Val = CX4_readw((CX4_read(ptr + 1) << 4) + 1);
173      cx4.C4WFY2Val = CX4_readw((CX4_read(ptr + 1) << 4) + 5);
174      CX4_C4CalcWireFrame();
175      CX4_writew(machine, ptr2 + 0x600, cx4.C4WFDist ? cx4.C4WFDist : 1);
176      CX4_writew(machine, ptr2 + 0x602, cx4.C4WFXVal);
177      CX4_writew(machine, ptr2 + 0x605, cx4.C4WFYVal);
178   }
179}
180
181//Scale and Rotate
182static void CX4_op00_07(void)
183{
184   CX4_C4DoScaleRotate(64);
185}
186
187//Draw Wireframe
188static void CX4_op00_08(running_machine &machine)
189{
190   CX4_C4DrawWireFrame(machine);
191}
192
193//Disintegrate
194static void CX4_op00_0b(running_machine &machine)
195{
196   UINT8  width, height;
197   UINT32 startx, starty;
198   UINT32 srcptr;
199   UINT32 x, y;
200   INT32  scalex, scaley;
201   INT32  cx, cy;
202   INT32  i, j;
203
204   width  = CX4_read(0x1f89);
205   height = CX4_read(0x1f8c);
206   cx     = CX4_readw(0x1f80);
207   cy     = CX4_readw(0x1f83);
208
209   scalex = (INT16)CX4_readw(0x1f86);
210   scaley = (INT16)CX4_readw(0x1f8f);
211   startx = -cx * scalex + (cx << 8);
212   starty = -cy * scaley + (cy << 8);
213   srcptr = 0x600;
214
215   for(i = 0; i < (width * height) >> 1; i++)
216   {
217      CX4_write(machine, i, 0);
218   }
219
220   for(y = starty, i = 0;i < height; i++, y += scaley)
221   {
222      for(x = startx, j = 0;j < width; j++, x += scalex)
223      {
224         if((x >> 8) < width && (y >> 8) < height && (y >> 8) * width + (x >> 8) < 0x2000)
225         {
226            UINT8 pixel = (j & 1) ? (cx4.ram[srcptr] >> 4) : (cx4.ram[srcptr]);
227            INT32 index = (y >> 11) * width * 4 + (x >> 11) * 32 + ((y >> 8) & 7) * 2;
228            UINT8 mask = 0x80 >> ((x >> 8) & 7);
229
230            if(pixel & 1) cx4.ram[index     ] |= mask;
231            if(pixel & 2) cx4.ram[index +  1] |= mask;
232            if(pixel & 4) cx4.ram[index + 16] |= mask;
233            if(pixel & 8) cx4.ram[index + 17] |= mask;
234         }
235         if(j & 1)
236         {
237            srcptr++;
238         }
239      }
240   }
241}
242
243//Bitplane Wave
244static void CX4_op00_0c(running_machine &machine)
245{
246   int i, j;
247   UINT32 destptr = 0;
248   UINT32 waveptr = CX4_read(0x1f83);
249   UINT16 mask1   = 0xc0c0;
250   UINT16 mask2   = 0x3f3f;
251
252   for(j = 0; j < 0x10; j++)
253   {
254      do
255      {
256         INT16 height = -((INT8)CX4_read(waveptr + 0xb00)) - 16;
257         for(i = 0; i < 40; i++)
258         {
259            UINT16 temp = CX4_readw(destptr + CX4_wave_data[i]) & mask2;
260            if(height >= 0)
261            {
262               if(height < 8)
263               {
264                  temp |= mask1 & CX4_readw(0xa00 + height * 2);
265               }
266               else
267               {
268                  temp |= mask1 & 0xff00;
269               }
270            }
271            CX4_writew(machine, destptr + CX4_wave_data[i], temp);
272            height++;
273         }
274         waveptr = (waveptr + 1) & 0x7f;
275         mask1   = (mask1 >> 2) | (mask1 << 6);
276         mask2   = (mask2 >> 2) | (mask2 << 6);
277      } while(mask1 != 0xc0c0);
278      destptr += 16;
279
280      do
281      {
282         INT16 height = -((INT8)CX4_read(waveptr + 0xb00)) - 16;
283         for(i = 0; i < 40; i++)
284         {
285            UINT16 temp = CX4_readw(destptr + CX4_wave_data[i]) & mask2;
286            if(height >= 0)
287            {
288               if(height < 8)
289               {
290                  temp |= mask1 & CX4_readw(0xa10 + height * 2);
291               }
292               else
293               {
294                  temp |= mask1 & 0xff00;
295               }
296            }
297            CX4_writew(machine, destptr + CX4_wave_data[i], temp);
298            height++;
299         }
300         waveptr = (waveptr + 1) & 0x7f;
301         mask1   = (mask1 >> 2) | (mask1 << 6);
302         mask2   = (mask2 >> 2) | (mask2 << 6);
303      } while(mask1 != 0xc0c0);
304      destptr += 16;
305   }
306}
Property changes on: trunk/src/mess/machine/cx4oam.c
Added: svn:mime-type
   + text/plain
Added: svn:eol-style
   + native
trunk/src/mess/machine/cx4data.c
r0r21590
1/***************************************************************************
2
3    cx4data.c
4
5    Code based on original work by zsKnight, anomie and Nach.
6    This implementation is based on C++ "cx4*.cpp" by byuu
7    (up to date with source v 0.49).
8
9***************************************************************************/
10
11static const UINT8 CX4_immediate_data[48] =
12{
13   0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
14   0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x80, 0xff, 0xff, 0x7f,
15   0x00, 0x80, 0x00, 0xff, 0x7f, 0x00, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0xff,
16   0x00, 0x00, 0x01, 0xff, 0xff, 0xfe, 0x00, 0x01, 0x00, 0xff, 0xfe, 0x00
17};
18
19static const UINT16 CX4_wave_data[40] =
20{
21   0x0000, 0x0002, 0x0004, 0x0006, 0x0008, 0x000a, 0x000c, 0x000e,
22   0x0200, 0x0202, 0x0204, 0x0206, 0x0208, 0x020a, 0x020c, 0x020e,
23   0x0400, 0x0402, 0x0404, 0x0406, 0x0408, 0x040a, 0x040c, 0x040e,
24   0x0600, 0x0602, 0x0604, 0x0606, 0x0608, 0x060a, 0x060c, 0x060e,
25   0x0800, 0x0802, 0x0804, 0x0806, 0x0808, 0x080a, 0x080c, 0x080e
26};
27
28static const UINT32 CX4_sin_table[256] =
29{
30   0x000000, 0x000324, 0x000648, 0x00096c, 0x000c8f, 0x000fb2, 0x0012d5, 0x0015f6,
31   0x001917, 0x001c37, 0x001f56, 0x002273, 0x002590, 0x0028aa, 0x002bc4, 0x002edb,
32   0x0031f1, 0x003505, 0x003817, 0x003b26, 0x003e33, 0x00413e, 0x004447, 0x00474d,
33   0x004a50, 0x004d50, 0x00504d, 0x005347, 0x00563e, 0x005931, 0x005c22, 0x005f0e,
34   0x0061f7, 0x0064dc, 0x0067bd, 0x006a9b, 0x006d74, 0x007049, 0x007319, 0x0075e5,
35   0x0078ad, 0x007b70, 0x007e2e, 0x0080e7, 0x00839c, 0x00864b, 0x0088f5, 0x008b9a,
36   0x008e39, 0x0090d3, 0x009368, 0x0095f6, 0x00987f, 0x009b02, 0x009d7f, 0x009ff6,
37   0x00a267, 0x00a4d2, 0x00a736, 0x00a994, 0x00abeb, 0x00ae3b, 0x00b085, 0x00b2c8,
38   0x00b504, 0x00b73a, 0x00b968, 0x00bb8f, 0x00bdae, 0x00bfc7, 0x00c1d8, 0x00c3e2,
39   0x00c5e4, 0x00c7de, 0x00c9d1, 0x00cbbb, 0x00cd9f, 0x00cf7a, 0x00d14d, 0x00d318,
40   0x00d4db, 0x00d695, 0x00d848, 0x00d9f2, 0x00db94, 0x00dd2d, 0x00debe, 0x00e046,
41   0x00e1c5, 0x00e33c, 0x00e4aa, 0x00e60f, 0x00e76b, 0x00e8bf, 0x00ea09, 0x00eb4b,
42   0x00ec83, 0x00edb2, 0x00eed8, 0x00eff5, 0x00f109, 0x00f213, 0x00f314, 0x00f40b,
43   0x00f4fa, 0x00f5de, 0x00f6ba, 0x00f78b, 0x00f853, 0x00f912, 0x00f9c7, 0x00fa73,
44   0x00fb14, 0x00fbac, 0x00fc3b, 0x00fcbf, 0x00fd3a, 0x00fdab, 0x00fe13, 0x00fe70,
45   0x00fec4, 0x00ff0e, 0x00ff4e, 0x00ff84, 0x00ffb1, 0x00ffd3, 0x00ffec, 0x00fffb,
46   0x000000, 0xfffcdb, 0xfff9b7, 0xfff693, 0xfff370, 0xfff04d, 0xffed2a, 0xffea09,
47   0xffe6e8, 0xffe3c8, 0xffe0a9, 0xffdd8c, 0xffda6f, 0xffd755, 0xffd43b, 0xffd124,
48   0xffce0e, 0xffcafa, 0xffc7e8, 0xffc4d9, 0xffc1cc, 0xffbec1, 0xffbbb8, 0xffb8b2,
49   0xffb5af, 0xffb2af, 0xffafb2, 0xffacb8, 0xffa9c1, 0xffa6ce, 0xffa3dd, 0xffa0f1,
50   0xff9e08, 0xff9b23, 0xff9842, 0xff9564, 0xff928b, 0xff8fb6, 0xff8ce6, 0xff8a1a,
51   0xff8752, 0xff848f, 0xff81d1, 0xff7f18, 0xff7c63, 0xff79b4, 0xff770a, 0xff7465,
52   0xff71c6, 0xff6f2c, 0xff6c97, 0xff6a09, 0xff6780, 0xff64fd, 0xff6280, 0xff6009,
53   0xff5d98, 0xff5b2d, 0xff58c9, 0xff566b, 0xff5414, 0xff51c4, 0xff4f7a, 0xff4d37,
54   0xff4afb, 0xff48c5, 0xff4697, 0xff4470, 0xff4251, 0xff4038, 0xff3e27, 0xff3c1e,
55   0xff3a1b, 0xff3821, 0xff362e, 0xff3444, 0xff3260, 0xff3085, 0xff2eb2, 0xff2ce7,
56   0xff2b24, 0xff296a, 0xff27b7, 0xff260d, 0xff246b, 0xff22d2, 0xff2141, 0xff1fb9,
57   0xff1e3a, 0xff1cc3, 0xff1b55, 0xff19f0, 0xff1894, 0xff1740, 0xff15f6, 0xff14b4,
58   0xff137c, 0xff124d, 0xff1127, 0xff100a, 0xff0ef6, 0xff0dec, 0xff0ceb, 0xff0bf4,
59   0xff0b05, 0xff0a21, 0xff0945, 0xff0874, 0xff07ac, 0xff06ed, 0xff0638, 0xff058d,
60   0xff04eb, 0xff0453, 0xff03c4, 0xff0340, 0xff02c5, 0xff0254, 0xff01ec, 0xff018f,
61   0xff013b, 0xff00f1, 0xff00b1, 0xff007b, 0xff004e, 0xff002c, 0xff0013, 0xff0004
62};
63
64static const INT16 CX4_SinTable[512] =
65{
66         0,   402,    804,   1206,    1607,   2009,   2410,   2811,
67      3211,    3611,   4011,   4409,   4808,   5205,   5602,   5997,
68      6392,    6786,   7179,   7571,   7961,   8351,   8739,   9126,
69      9512,    9896,  10278,  10659,  11039,  11416,  11793,  12167,
70      12539,  12910,  13278,  13645,  14010,  14372,  14732,  15090,
71      15446,  15800,  16151,  16499,  16846,  17189,  17530,  17869,
72      18204,  18537,  18868,  19195,  19519,  19841,  20159,  20475,
73      20787,  21097,  21403,  21706,  22005,  22301,  22594,  22884,
74      23170,  23453,  23732,  24007,  24279,  24547,  24812,  25073,
75      25330,  25583,  25832,  26077,  26319,  26557,  26790,  27020,
76      27245,  27466,  27684,  27897,  28106,  28310,  28511,  28707,
77      28898,  29086,  29269,  29447,  29621,  29791,  29956,  30117,
78      30273,  30425,  30572,  30714,  30852,  30985,  31114,  31237,
79      31357,  31471,  31581,  31685,  31785,  31881,  31971,  32057,
80      32138,  32214,  32285,  32351,  32413,  32469,  32521,  32568,
81      32610,  32647,  32679,  32706,  32728,  32745,  32758,  32765,
82      32767,  32765,  32758,  32745,  32728,  32706,  32679,  32647,
83      32610,  32568,  32521,  32469,  32413,  32351,  32285,  32214,
84      32138,  32057,  31971,  31881,  31785,  31685,  31581,  31471,
85      31357,  31237,  31114,  30985,  30852,  30714,  30572,  30425,
86      30273,  30117,  29956,  29791,  29621,  29447,  29269,  29086,
87      28898,  28707,  28511,  28310,  28106,  27897,  27684,  27466,
88      27245,  27020,  26790,  26557,  26319,  26077,  25832,  25583,
89      25330,  25073,  24812,  24547,  24279,  24007,  23732,  23453,
90      23170,  22884,  22594,  22301,  22005,  21706,  21403,  21097,
91      20787,  20475,  20159,  19841,  19519,  19195,  18868,  18537,
92      18204,  17869,  17530,  17189,  16846,  16499,  16151,  15800,
93      15446,  15090,  14732,  14372,  14010,  13645,  13278,  12910,
94      12539,  12167,  11793,  11416,  11039,  10659,  10278,   9896,
95      9512,    9126,   8739,   8351,   7961,   7571,   7179,   6786,
96      6392,    5997,   5602,   5205,   4808,   4409,   4011,   3611,
97      3211,    2811,   2410,   2009,   1607,   1206,    804,    402,
98         0,   -402,   -804,  -1206,  -1607,  -2009,  -2410,  -2811,
99      -3211,  -3611,  -4011,  -4409,  -4808,  -5205,  -5602,  -5997,
100      -6392,  -6786,  -7179,  -7571,  -7961,  -8351,  -8739,  -9126,
101      -9512,  -9896,  -10278, -10659, -11039, -11416, -11793, -12167,
102   -12539, -12910, -13278, -13645, -14010, -14372, -14732, -15090,
103   -15446, -15800, -16151, -16499, -16846, -17189, -17530, -17869,
104   -18204, -18537, -18868, -19195, -19519, -19841, -20159, -20475,
105   -20787, -21097, -21403, -21706, -22005, -22301, -22594, -22884,
106   -23170, -23453, -23732, -24007, -24279, -24547, -24812, -25073,
107   -25330, -25583, -25832, -26077, -26319, -26557, -26790, -27020,
108   -27245, -27466, -27684, -27897, -28106, -28310, -28511, -28707,
109   -28898, -29086, -29269, -29447, -29621, -29791, -29956, -30117,
110   -30273, -30425, -30572, -30714, -30852, -30985, -31114, -31237,
111   -31357, -31471, -31581, -31685, -31785, -31881, -31971, -32057,
112   -32138, -32214, -32285, -32351, -32413, -32469, -32521, -32568,
113   -32610, -32647, -32679, -32706, -32728, -32745, -32758, -32765,
114   -32767, -32765, -32758, -32745, -32728, -32706, -32679, -32647,
115   -32610, -32568, -32521, -32469, -32413, -32351, -32285, -32214,
116   -32138, -32057, -31971, -31881, -31785, -31685, -31581, -31471,
117   -31357, -31237, -31114, -30985, -30852, -30714, -30572, -30425,
118   -30273, -30117, -29956, -29791, -29621, -29447, -29269, -29086,
119   -28898, -28707, -28511, -28310, -28106, -27897, -27684, -27466,
120   -27245, -27020, -26790, -26557, -26319, -26077, -25832, -25583,
121   -25330, -25073, -24812, -24547, -24279, -24007, -23732, -23453,
122   -23170, -22884, -22594, -22301, -22005, -21706, -21403, -21097,
123   -20787, -20475, -20159, -19841, -19519, -19195, -18868, -18537,
124   -18204, -17869, -17530, -17189, -16846, -16499, -16151, -15800,
125   -15446, -15090, -14732, -14372, -14010, -13645, -13278, -12910,
126   -12539, -12167, -11793, -11416, -11039, -10659, -10278, -9896,
127      -9512,  -9126,  -8739,  -8351,  -7961,  -7571,  -7179,  -6786,
128      -6392,  -5997,  -5602,  -5205,  -4808,  -4409,  -4011,  -3611,
129      -3211,  -2811,  -2410,  -2009,  -1607,  -1206,   -804,   -402
130};
131
132static const INT16 CX4_CosTable[512] =
133{
134      32767,  32765,  32758,  32745,  32728,  32706,  32679,  32647,
135      32610,  32568,  32521,  32469,  32413,  32351,  32285,  32214,
136      32138,  32057,  31971,  31881,  31785,  31685,  31581,  31471,
137      31357,  31237,  31114,  30985,  30852,  30714,  30572,  30425,
138      30273,  30117,  29956,  29791,  29621,  29447,  29269,  29086,
139      28898,  28707,  28511,  28310,  28106,  27897,  27684,  27466,
140      27245,  27020,  26790,  26557,  26319,  26077,  25832,  25583,
141      25330,  25073,  24812,  24547,  24279,  24007,  23732,  23453,
142      23170,  22884,  22594,  22301,  22005,  21706,  21403,  21097,
143      20787,  20475,  20159,  19841,  19519,  19195,  18868,  18537,
144      18204,  17869,  17530,  17189,  16846,  16499,  16151,  15800,
145      15446,  15090,  14732,  14372,  14010,  13645,  13278,  12910,
146      12539,  12167,  11793,  11416,  11039,  10659,  10278,   9896,
147      9512,    9126,   8739,   8351,   7961,   7571,   7179,   6786,
148      6392,    5997,   5602,   5205,   4808,   4409,   4011,   3611,
149      3211,    2811,   2410,   2009,   1607,   1206,    804,    402,
150         0,   -402,   -804,  -1206,  -1607,  -2009,  -2410,  -2811,
151      -3211,  -3611,  -4011,  -4409,  -4808,  -5205,  -5602,  -5997,
152      -6392,  -6786,  -7179,  -7571,  -7961,  -8351,  -8739,  -9126,
153      -9512,  -9896, -10278, -10659, -11039, -11416, -11793, -12167,
154   -12539, -12910, -13278, -13645, -14010, -14372, -14732, -15090,
155   -15446, -15800, -16151, -16499, -16846, -17189, -17530, -17869,
156   -18204, -18537, -18868, -19195, -19519, -19841, -20159, -20475,
157   -20787, -21097, -21403, -21706, -22005, -22301, -22594, -22884,
158   -23170, -23453, -23732, -24007, -24279, -24547, -24812, -25073,
159   -25330, -25583, -25832, -26077, -26319, -26557, -26790, -27020,
160   -27245, -27466, -27684, -27897, -28106, -28310, -28511, -28707,
161   -28898, -29086, -29269, -29447, -29621, -29791, -29956, -30117,
162   -30273, -30425, -30572, -30714, -30852, -30985, -31114, -31237,
163   -31357, -31471, -31581, -31685, -31785, -31881, -31971, -32057,
164   -32138, -32214, -32285, -32351, -32413, -32469, -32521, -32568,
165   -32610, -32647, -32679, -32706, -32728, -32745, -32758, -32765,
166   -32767, -32765, -32758, -32745, -32728, -32706, -32679, -32647,
167   -32610, -32568, -32521, -32469, -32413, -32351, -32285, -32214,
168   -32138, -32057, -31971, -31881, -31785, -31685, -31581, -31471,
169   -31357, -31237, -31114, -30985, -30852, -30714, -30572, -30425,
170   -30273, -30117, -29956, -29791, -29621, -29447, -29269, -29086,
171   -28898, -28707, -28511, -28310, -28106, -27897, -27684, -27466,
172   -27245, -27020, -26790, -26557, -26319, -26077, -25832, -25583,
173   -25330, -25073, -24812, -24547, -24279, -24007, -23732, -23453,
174   -23170, -22884, -22594, -22301, -22005, -21706, -21403, -21097,
175   -20787, -20475, -20159, -19841, -19519, -19195, -18868, -18537,
176   -18204, -17869, -17530, -17189, -16846, -16499, -16151, -15800,
177   -15446, -15090, -14732, -14372, -14010, -13645, -13278, -12910,
178   -12539, -12167, -11793, -11416, -11039, -10659, -10278, -9896,
179      -9512,  -9126,  -8739,  -8351,  -7961,  -7571,  -7179,  -6786,
180      -6392,  -5997,  -5602,  -5205,  -4808,  -4409,  -4011,  -3611,
181      -3211,  -2811,  -2410,  -2009,  -1607,  -1206,   -804,   -402,
182         0,    402,    804,   1206,   1607,   2009,   2410,   2811,
183      3211,    3611,   4011,   4409,   4808,   5205,   5602,   5997,
184      6392,    6786,   7179,   7571,   7961,   8351,   8739,   9126,
185      9512,    9896,  10278,  10659,  11039,  11416,  11793,  12167,
186      12539,  12910,  13278,  13645,  14010,  14372,  14732,  15090,
187      15446,  15800,  16151,  16499,  16846,  17189,  17530,  17869,
188      18204,  18537,  18868,  19195,  19519,  19841,  20159,  20475,
189      20787,  21097,  21403,  21706,  22005,  22301,  22594,  22884,
190      23170,  23453,  23732,  24007,  24279,  24547,  24812,  25073,
191      25330,  25583,  25832,  26077,  26319,  26557,  26790,  27020,
192      27245,  27466,  27684,  27897,  28106,  28310,  28511,  28707,
193      28898,  29086,  29269,  29447,  29621,  29791,  29956,  30117,
194      30273,  30425,  30572,  30714,  30852,  30985,  31114,  31237,
195      31357,  31471,  31581,  31685,  31785,  31881,  31971,  32057,
196      32138,  32214,  32285,  32351,  32413,  32469,  32521,  32568,
197      32610,  32647,  32679,  32706,  32728,  32745,  32758,  32765
198};
Property changes on: trunk/src/mess/machine/cx4data.c
Added: svn:eol-style
   + native
Added: svn:mime-type
   + text/plain
trunk/src/mess/machine/snescx4.c
r0r21590
1/***************************************************************************
2
3    snescx4.c
4
5    File to handle emulation of the SNES "CX4" add-on chip.
6
7    Code based on original work by zsKnight, anomie and Nach.
8    This implementation is based on C++ "cx4*.cpp" by byuu
9    (up to date with source v 0.49).
10
11***************************************************************************/
12
13#include "emu.h"
14#include "snescx4.h"
15
16static CX4 cx4;
17
18static UINT16 CX4_readw(UINT16 addr);
19static UINT32 CX4_readl(UINT16 addr);
20
21static void CX4_writew(running_machine &machine, UINT16 addr, UINT16 data);
22//static void CX4_writel(running_machine &machine, UINT16 addr, UINT32 data);
23
24static void CX4_C4DrawLine(INT32 X1, INT32 Y1, INT16 Z1, INT32 X2, INT32 Y2, INT16 Z2, UINT8 Color);
25
26#include "cx4data.c"
27#include "cx4fn.c"
28
29static UINT32 CX4_ldr(UINT8 r)
30{
31   UINT16 addr = 0x0080 + (r * 3);
32   return (cx4.reg[addr + 0] <<  0)
33         | (cx4.reg[addr + 1] <<  8)
34         | (cx4.reg[addr + 2] << 16);
35}
36
37static void CX4_str(UINT8 r, UINT32 data)
38{
39   UINT16 addr = 0x0080 + (r * 3);
40   cx4.reg[addr + 0] = (data >>  0);
41   cx4.reg[addr + 1] = (data >>  8);
42   cx4.reg[addr + 2] = (data >> 16);
43}
44
45static void CX4_mul(UINT32 x, UINT32 y, UINT32 *rl, UINT32 *rh)
46{
47   INT64 rx = x & 0xffffff;
48   INT64 ry = y & 0xffffff;
49   if(rx & 0x800000)rx |= ~0x7fffff;
50   if(ry & 0x800000)ry |= ~0x7fffff;
51
52   rx *= ry;
53
54   *rl = (rx)       & 0xffffff;
55   *rh = (rx >> 24) & 0xffffff;
56}
57
58static UINT32 CX4_sin(UINT32 rx)
59{
60   cx4.r0 = rx & 0x1ff;
61   if(cx4.r0 & 0x100)
62   {
63      cx4.r0 ^= 0x1ff;
64   }
65   if(cx4.r0 & 0x080)
66   {
67      cx4.r0 ^= 0x0ff;
68   }
69   if(rx & 0x100)
70   {
71      return CX4_sin_table[cx4.r0 + 0x80];
72   }
73   else
74   {
75      return CX4_sin_table[cx4.r0];
76   }
77}
78
79static UINT32 CX4_cos(UINT32 rx)
80{
81   return CX4_sin(rx + 0x080);
82}
83
84static void CX4_immediate_reg(UINT32 start)
85{
86   UINT32 i = 0;
87   cx4.r0 = CX4_ldr(0);
88   for(i = start; i < 48; i++)
89   {
90      if((cx4.r0 & 0x0fff) < 0x0c00)
91      {
92         cx4.ram[cx4.r0 & 0x0fff] = CX4_immediate_data[i];
93      }
94      cx4.r0++;
95   }
96   CX4_str(0, cx4.r0);
97}
98
99static void CX4_transfer_data(running_machine &machine)
100{
101   UINT32 src;
102   UINT16 dest, count;
103   UINT32 i;
104
105   src   = (cx4.reg[0x40]) | (cx4.reg[0x41] << 8) | (cx4.reg[0x42] << 16);
106   count = (cx4.reg[0x43]) | (cx4.reg[0x44] << 8);
107   dest  = (cx4.reg[0x45]) | (cx4.reg[0x46] << 8);
108
109   address_space &space = machine.device<cpu_device>("maincpu")->space(AS_PROGRAM);
110   for(i=0;i<count;i++)
111   {
112      CX4_write(machine, dest++, space.read_byte(src++));
113   }
114}
115
116#include "cx4oam.c"
117#include "cx4ops.c"
118
119void CX4_write(running_machine &machine, UINT32 addr, UINT8 data)
120{
121   addr &= 0x1fff;
122
123   if(addr < 0x0c00)
124   {
125      //ram
126      cx4.ram[addr] = data;
127      return;
128   }
129
130   if(addr < 0x1f00)
131   {
132      //unmapped
133      return;
134   }
135
136   //command register
137   cx4.reg[addr & 0xff] = data;
138
139   if(addr == 0x1f47)
140   {
141      //memory transfer
142      CX4_transfer_data(machine);
143      return;
144   }
145
146   if(addr == 0x1f4f)
147   {
148      //c4 command
149      if(cx4.reg[0x4d] == 0x0e && !(data & 0xc3))
150      {
151         //c4 test command
152         cx4.reg[0x80] = data >> 2;
153         return;
154      }
155
156      switch(data)
157      {
158         case 0x00: CX4_op00(machine); break;
159         case 0x01: CX4_op01(machine); break;
160         case 0x05: CX4_op05(machine); break;
161         case 0x0d: CX4_op0d(machine); break;
162         case 0x10: CX4_op10(); break;
163         case 0x13: CX4_op13(); break;
164         case 0x15: CX4_op15(machine); break;
165         case 0x1f: CX4_op1f(machine); break;
166         case 0x22: CX4_op22(); break;
167         case 0x25: CX4_op25(); break;
168         case 0x2d: CX4_op2d(machine); break;
169         case 0x40: CX4_op40(); break;
170         case 0x54: CX4_op54(); break;
171         case 0x5c: CX4_op5c(); break;
172         case 0x5e: CX4_op5e(); break;
173         case 0x60: CX4_op60(); break;
174         case 0x62: CX4_op62(); break;
175         case 0x64: CX4_op64(); break;
176         case 0x66: CX4_op66(); break;
177         case 0x68: CX4_op68(); break;
178         case 0x6a: CX4_op6a(); break;
179         case 0x6c: CX4_op6c(); break;
180         case 0x6e: CX4_op6e(); break;
181         case 0x70: CX4_op70(); break;
182         case 0x72: CX4_op72(); break;
183         case 0x74: CX4_op74(); break;
184         case 0x76: CX4_op76(); break;
185         case 0x78: CX4_op78(); break;
186         case 0x7a: CX4_op7a(); break;
187         case 0x7c: CX4_op7c(); break;
188         case 0x89: CX4_op89(); break;
189      }
190   }
191}
192
193#ifdef UNUSED_FUNCTION
194void CX4_writeb(running_machine &machine, UINT16 addr, UINT8 data)
195{
196   CX4_write(machine, addr,     data);
197}
198#endif
199
200static void CX4_writew(running_machine &machine, UINT16 addr, UINT16 data)
201{
202   CX4_write(machine, addr + 0, data >> 0);
203   CX4_write(machine, addr + 1, data >> 8);
204}
205
206#ifdef UNUSED_FUNCTION
207void CX4_writel(running_machine &machine, UINT16 addr, UINT32 data)
208{
209   CX4_write(machine, addr + 0, data >>  0);
210   CX4_write(machine, addr + 1, data >>  8);
211   CX4_write(machine, addr + 2, data >> 16);
212}
213#endif
214
215UINT8 CX4_read(UINT32 addr)
216{
217   addr &= 0x1fff;
218
219   if(addr < 0x0c00)
220   {
221      return cx4.ram[addr];
222   }
223
224   if(addr >= 0x1f00)
225   {
226      return cx4.reg[addr & 0xff];
227   }
228
229   return 0xff;
230}
231
232#ifdef UNUSED_FUNCTION
233UINT8 CX4_readb(UINT16 addr)
234{
235   return CX4_read(addr);
236}
237#endif
238
239static UINT16 CX4_readw(UINT16 addr)
240{
241   return CX4_read(addr) | (CX4_read(addr + 1) << 8);
242}
243
244static UINT32 CX4_readl(UINT16 addr)
245{
246   return CX4_read(addr) | (CX4_read(addr + 1) << 8) | (CX4_read(addr + 2) << 16);
247}
248
249#ifdef UNUSED_FUNCTION
250void CX4_reset()
251{
252   memset(cx4.ram, 0, 0x0c00);
253   memset(cx4.reg, 0, 0x0100);
254}
255#endif
Property changes on: trunk/src/mess/machine/snescx4.c
Added: svn:mime-type
   + text/plain
Added: svn:eol-style
   + native
trunk/src/mess/machine/snescx4.h
r0r21590
1/***************************************************************************
2
3    snescx4.h
4
5    Code based on original work by zsKnight, anomie and Nach.
6    This implementation is based on C++ "cx4*.cpp" by byuu
7    (up to date with source v 0.49).
8
9***************************************************************************/
10
11struct CX4
12{
13      UINT8 ram[0x0c00];
14      UINT8 reg[0x0100];
15      UINT32 r0, r1, r2,  r3,  r4,  r5,  r6,  r7,
16               r8, r9, r10, r11, r12, r13, r14, r15;
17
18      INT16 C4WFXVal, C4WFYVal, C4WFZVal, C4WFX2Val, C4WFY2Val, C4WFDist, C4WFScale;
19      INT16 C41FXVal, C41FYVal, C41FAngleRes, C41FDist, C41FDistVal;
20
21      double tanval;
22      double c4x, c4y, c4z;
23      double c4x2, c4y2, c4z2;
24};
Property changes on: trunk/src/mess/machine/snescx4.h
Added: svn:mime-type
   + text/plain
Added: svn:eol-style
   + native
trunk/src/mess/machine/snescart.c
r21589r21590
13051305   }
13061306
13071307}
1308
1309// add-on chip emulators
1310#include "machine/snesobc1.c"
1311#include "machine/snescx4.c"
1312#include "machine/snesrtc.c"
1313#include "machine/snessdd1.c"
1314#include "machine/snes7110.c"
1315
trunk/src/mess/machine/snescart.h
r21589r21590
66#ifndef _SNESCART_H
77#define _SNESCART_H
88
9#include "imagedev/cartslot.h"
10
119void snes_machine_stop(running_machine &machine);
1210void sufami_machine_stop(running_machine &machine);
1311
r21589r21590
1513MACHINE_CONFIG_EXTERN( snesp_cartslot );
1614MACHINE_CONFIG_EXTERN( sufami_cartslot );
1715
16
17// add-on chips IO
18void srtc_write(running_machine &machine, UINT16 addr, UINT8 data);
19UINT8 srtc_read(address_space &space, UINT16 addr);
20void srtc_init(running_machine &machine);
21extern DECLARE_READ8_HANDLER(obc1_read);
22extern DECLARE_WRITE8_HANDLER(obc1_write);
23void obc1_init(running_machine &machine);
24UINT8 CX4_read(UINT32 addr);
25void CX4_write(running_machine &machine, UINT32 addr, UINT8 data);
26UINT8 sdd1_mmio_read(address_space &space, UINT32 addr);
27void sdd1_mmio_write(address_space &space, UINT32 addr, UINT8 data);
28void sdd1_init(running_machine& machine);
29UINT8 sdd1_read(running_machine& machine, UINT32 addr);
30UINT8 spc7110_mmio_read(address_space &space, UINT32 addr);
31void spc7110_mmio_write(running_machine &machine, UINT32 addr, UINT8 data);
32UINT8 spc7110_bank7_read(address_space &space, UINT32 offset);
33void spc7110_init(running_machine& machine);
34void spc7110rtc_init(running_machine& machine);
35
36
37
1838#endif /* _SNESCART_H */
trunk/src/mess/machine/cx4fn.c
r0r21590
1/***************************************************************************
2
3    cx4fn.c
4
5    Code based on original work by zsKnight, anomie and Nach.
6    This implementation is based on C++ "cx4*.cpp" by byuu.
7    (up to date with source v 0.49).
8
9***************************************************************************/
10
11#include <math.h>
12#define CX4_Tan(a) (CX4_CosTable[a] ? ((((INT32)CX4_SinTable[a]) << 16) / CX4_CosTable[a]) : 0x80000000)
13#define CX4_sar(b, n) ((b) >> (n))
14#ifdef PI
15#undef PI
16#endif
17#define PI 3.1415926535897932384626433832795
18
19//Wireframe Helpers
20static void CX4_C4TransfWireFrame(void)
21{
22   cx4.c4x = (double)cx4.C4WFXVal;
23   cx4.c4y = (double)cx4.C4WFYVal;
24   cx4.c4z = (double)cx4.C4WFZVal - 0x95;
25
26   //Rotate X
27   cx4.tanval = -(double)cx4.C4WFX2Val * PI * 2 / 128;
28   cx4.c4y2   = cx4.c4y * cos(cx4.tanval) - cx4.c4z * sin(cx4.tanval);
29   cx4.c4z2   = cx4.c4y * sin(cx4.tanval) + cx4.c4z * cos(cx4.tanval);
30
31   //Rotate Y
32   cx4.tanval = -(double)cx4.C4WFY2Val * PI * 2 / 128;
33   cx4.c4x2   = cx4.c4x * cos(cx4.tanval)  + cx4.c4z2 * sin(cx4.tanval);
34   cx4.c4z    = cx4.c4x * -sin(cx4.tanval) + cx4.c4z2 * cos(cx4.tanval);
35
36   //Rotate Z
37   cx4.tanval = -(double)cx4.C4WFDist * PI * 2 / 128;
38   cx4.c4x    = cx4.c4x2 * cos(cx4.tanval) - cx4.c4y2 * sin(cx4.tanval);
39   cx4.c4y    = cx4.c4x2 * sin(cx4.tanval) + cx4.c4y2 * cos(cx4.tanval);
40
41   //Scale
42   cx4.C4WFXVal = (INT16)(cx4.c4x * cx4.C4WFScale / (0x90 * (cx4.c4z + 0x95)) * 0x95);
43   cx4.C4WFYVal = (INT16)(cx4.c4y * cx4.C4WFScale / (0x90 * (cx4.c4z + 0x95)) * 0x95);
44}
45
46static void CX4_C4CalcWireFrame(void)
47{
48   cx4.C4WFXVal = cx4.C4WFX2Val - cx4.C4WFXVal;
49   cx4.C4WFYVal = cx4.C4WFY2Val - cx4.C4WFYVal;
50
51   if(abs(cx4.C4WFXVal) > abs(cx4.C4WFYVal))
52   {
53      cx4.C4WFDist = abs(cx4.C4WFXVal) + 1;
54      cx4.C4WFYVal = (256 * (long)cx4.C4WFYVal) / abs(cx4.C4WFXVal);
55      cx4.C4WFXVal = (cx4.C4WFXVal < 0) ? -256 : 256;
56   }
57   else if(cx4.C4WFYVal != 0)
58   {
59      cx4.C4WFDist = abs(cx4.C4WFYVal) + 1;
60      cx4.C4WFXVal = (256 * (long)cx4.C4WFXVal) / abs(cx4.C4WFYVal);
61      cx4.C4WFYVal = (cx4.C4WFYVal < 0) ? -256 : 256;
62   }
63   else
64   {
65      cx4.C4WFDist = 0;
66   }
67}
68
69static void CX4_C4TransfWireFrame2(void)
70{
71   cx4.c4x = (double)cx4.C4WFXVal;
72   cx4.c4y = (double)cx4.C4WFYVal;
73   cx4.c4z = (double)cx4.C4WFZVal;
74
75   //Rotate X
76   cx4.tanval = -(double)cx4.C4WFX2Val * PI * 2 / 128;
77   cx4.c4y2   = cx4.c4y * cos(cx4.tanval) - cx4.c4z * sin(cx4.tanval);
78   cx4.c4z2   = cx4.c4y * sin(cx4.tanval) + cx4.c4z * cos(cx4.tanval);
79
80   //Rotate Y
81   cx4.tanval = -(double)cx4.C4WFY2Val * PI * 2 / 128;
82   cx4.c4x2   = cx4.c4x * cos(cx4.tanval)  + cx4.c4z2 * sin(cx4.tanval);
83   cx4.c4z    = cx4.c4x * -sin(cx4.tanval) + cx4.c4z2 * cos(cx4.tanval);
84
85   //Rotate Z
86   cx4.tanval = -(double)cx4.C4WFDist * PI * 2 / 128;
87   cx4.c4x    = cx4.c4x2 * cos(cx4.tanval) - cx4.c4y2 * sin(cx4.tanval);
88   cx4.c4y    = cx4.c4x2 * sin(cx4.tanval) + cx4.c4y2 * cos(cx4.tanval);
89
90   //Scale
91   cx4.C4WFXVal = (INT16)(cx4.c4x * cx4.C4WFScale / 0x100);
92   cx4.C4WFYVal = (INT16)(cx4.c4y * cx4.C4WFScale / 0x100);
93}
94
95static void CX4_C4DrawWireFrame(running_machine &machine)
96{
97   UINT32 line = CX4_readl(0x1f80);
98   UINT32 point1, point2;
99   INT16 X1, Y1, Z1;
100   INT16 X2, Y2, Z2;
101   UINT8 Color;
102   INT32 i;
103
104   address_space &space = machine.device<cpu_device>("maincpu")->space(AS_PROGRAM);
105   for(i = cx4.ram[0x0295]; i > 0; i--, line += 5)
106   {
107      if(space.read_byte(line) == 0xff &&
108         space.read_byte(line + 1) == 0xff)
109      {
110         INT32 tmp = line - 5;
111         while(space.read_byte(tmp + 2) == 0xff &&
112               space.read_byte(tmp + 3) == 0xff &&
113               (tmp + 2) >= 0)
114         {
115            tmp -= 5;
116         }
117         point1 = (CX4_read(0x1f82) << 16) |
118                  (space.read_byte(tmp + 2) << 8) |
119                  space.read_byte(tmp + 3);
120      }
121      else
122      {
123         point1 = (CX4_read(0x1f82) << 16) |
124                  (space.read_byte(line) << 8) |
125                  space.read_byte(line + 1);
126      }
127      point2 = (CX4_read(0x1f82) << 16) |
128               (space.read_byte(line + 2) << 8) |
129               space.read_byte(line + 3);
130
131      X1=(space.read_byte(point1 + 0) << 8) |
132         space.read_byte(point1 + 1);
133      Y1=(space.read_byte(point1 + 2) << 8) |
134         space.read_byte(point1 + 3);
135      Z1=(space.read_byte(point1 + 4) << 8) |
136         space.read_byte(point1 + 5);
137      X2=(space.read_byte(point2 + 0) << 8) |
138         space.read_byte(point2 + 1);
139      Y2=(space.read_byte(point2 + 2) << 8) |
140         space.read_byte(point2 + 3);
141      Z2=(space.read_byte(point2 + 4) << 8) |
142         space.read_byte(point2 + 5);
143      Color = space.read_byte(line + 4);
144      CX4_C4DrawLine(X1, Y1, Z1, X2, Y2, Z2, Color);
145   }
146}
147
148static void CX4_C4DrawLine(INT32 X1, INT32 Y1, INT16 Z1, INT32 X2, INT32 Y2, INT16 Z2, UINT8 Color)
149{
150   INT32 i;
151
152   //Transform coordinates
153   cx4.C4WFXVal  = (INT16)X1;
154   cx4.C4WFYVal  = (INT16)Y1;
155   cx4.C4WFZVal  = Z1;
156   cx4.C4WFScale = CX4_read(0x1f90);
157   cx4.C4WFX2Val = CX4_read(0x1f86);
158   cx4.C4WFY2Val = CX4_read(0x1f87);
159   cx4.C4WFDist  = CX4_read(0x1f88);
160   CX4_C4TransfWireFrame2();
161   X1 = (cx4.C4WFXVal + 48) << 8;
162   Y1 = (cx4.C4WFYVal + 48) << 8;
163
164   cx4.C4WFXVal = (INT16)X2;
165   cx4.C4WFYVal = (INT16)Y2;
166   cx4.C4WFZVal = Z2;
167   CX4_C4TransfWireFrame2();
168   X2 = (cx4.C4WFXVal + 48) << 8;
169   Y2 = (cx4.C4WFYVal + 48) << 8;
170
171   //Get line info
172   cx4.C4WFXVal  = (INT16)(X1 >> 8);
173   cx4.C4WFYVal  = (INT16)(Y1 >> 8);
174   cx4.C4WFX2Val = (INT16)(X2 >> 8);
175   cx4.C4WFY2Val = (INT16)(Y2 >> 8);
176   CX4_C4CalcWireFrame();
177   X2 = (INT16)cx4.C4WFXVal;
178   Y2 = (INT16)cx4.C4WFYVal;
179
180   //Render line
181   for(i = cx4.C4WFDist ? cx4.C4WFDist : 1; i > 0; i--)
182   {
183      if(X1 > 0xff && Y1 > 0xff && X1 < 0x6000 && Y1 < 0x6000)
184      {
185         UINT16 addr = (((Y1 >> 8) >> 3) << 8) - (((Y1 >> 8) >> 3) << 6) + (((X1 >> 8) >> 3) << 4) + ((Y1 >> 8) & 7) * 2;
186         UINT8 bit = 0x80 >> ((X1 >> 8) & 7);
187         cx4.ram[addr + 0x300] &= ~bit;
188         cx4.ram[addr + 0x301] &= ~bit;
189         if(Color & 1)
190         {
191            cx4.ram[addr + 0x300] |= bit;
192         }
193         if(Color & 2)
194         {
195            cx4.ram[addr + 0x301] |= bit;
196         }
197      }
198      X1 += X2;
199      Y1 += Y2;
200   }
201}
202
203static void CX4_C4DoScaleRotate(int row_padding)
204{
205   INT16 A, B, C, D;
206   INT32 x, y;
207
208   //Calculate Pixel Resolution
209   UINT8 w = CX4_read(0x1f89) & ~7;
210   UINT8 h = CX4_read(0x1f8c) & ~7;
211
212   INT32 Cx = (INT16)CX4_readw(0x1f83);
213   INT32 Cy = (INT16)CX4_readw(0x1f86);
214
215   INT32 LineX, LineY;
216   UINT32 X, Y;
217   UINT8 byte;
218   INT32 outidx = 0;
219   UINT8 bit    = 0x80;
220
221   //Calculate matrix
222   INT32 XScale = CX4_readw(0x1f8f);
223   INT32 YScale = CX4_readw(0x1f92);
224
225   if(XScale & 0x8000)
226   {
227      XScale = 0x7fff;
228   }
229   if(YScale & 0x8000)
230   {
231      YScale = 0x7fff;
232   }
233
234   if(CX4_readw(0x1f80) == 0)
235   { //no rotation
236      A = (INT16)XScale;
237      B = 0;
238      C = 0;
239      D = (INT16)YScale;
240   }
241   else if(CX4_readw(0x1f80) == 128)
242   { //90 degree rotation
243      A = 0;
244      B = (INT16)(-YScale);
245      C = (INT16)XScale;
246      D = 0;
247   }
248   else if(CX4_readw(0x1f80) == 256)
249   { //180 degree rotation
250      A = (INT16)(-XScale);
251      B = 0;
252      C = 0;
253      D = (INT16)(-YScale);
254   }
255   else if(CX4_readw(0x1f80) == 384)
256   { //270 degree rotation
257      A = 0;
258      B = (INT16)YScale;
259      C = (INT16)(-XScale);
260      D = 0;
261   }
262   else
263   {
264      A = (INT16)  CX4_sar(CX4_CosTable[CX4_readw(0x1f80) & 0x1ff] * XScale, 15);
265      B = (INT16)(-CX4_sar(CX4_SinTable[CX4_readw(0x1f80) & 0x1ff] * YScale, 15));
266      C = (INT16)  CX4_sar(CX4_SinTable[CX4_readw(0x1f80) & 0x1ff] * XScale, 15);
267      D = (INT16)  CX4_sar(CX4_CosTable[CX4_readw(0x1f80) & 0x1ff] * YScale, 15);
268   }
269
270   //Clear the output RAM
271   memset(cx4.ram, 0, (w + row_padding / 4) * h / 2);
272
273   //Calculate start position (i.e. (Ox, Oy) = (0, 0))
274   //The low 12 bits are fractional, so (Cx<<12) gives us the Cx we want in
275   //the function. We do Cx*A etc normally because the matrix parameters
276   //already have the fractional parts.
277   LineX = (Cx << 12) - Cx * A - Cx * B;
278   LineY = (Cy << 12) - Cy * C - Cy * D;
279
280   //Start loop
281   for(y = 0; y < h; y++)
282   {
283      X = LineX;
284      Y = LineY;
285      for(x = 0; x < w; x++)
286      {
287         if((X >> 12) >= w || (Y >> 12) >= h)
288         {
289            byte = 0;
290         }
291         else
292         {
293            UINT32 addr = (Y >> 12) * w + (X >> 12);
294            byte = CX4_read(0x600 + (addr >> 1));
295            if(addr & 1)
296            {
297               byte >>= 4;
298            }
299         }
300
301         //De-bitplanify
302         if(byte & 1) { cx4.ram[outidx     ] |= bit; }
303         if(byte & 2) { cx4.ram[outidx +  1] |= bit; }
304         if(byte & 4) { cx4.ram[outidx + 16] |= bit; }
305         if(byte & 8) { cx4.ram[outidx + 17] |= bit; }
306
307         bit >>= 1;
308         if(!bit)
309         {
310            bit     = 0x80;
311            outidx += 32;
312         }
313
314         X += A; //Add 1 to output x => add an A and a C
315         Y += C;
316      }
317      outidx += 2 + row_padding;
318      if(outidx & 0x10)
319      {
320         outidx &= ~0x10;
321      }
322      else
323      {
324         outidx -= w * 4 + row_padding;
325      }
326      LineX += B; //Add 1 to output y => add a B and a D
327      LineY += D;
328   }
329}
Property changes on: trunk/src/mess/machine/cx4fn.c
Added: svn:eol-style
   + native
Added: svn:mime-type
   + text/plain
trunk/src/mame/machine/cx4data.c
r21589r21590
1/***************************************************************************
2
3    cx4data.c
4
5    Code based on original work by zsKnight, anomie and Nach.
6    This implementation is based on C++ "cx4*.cpp" by byuu
7    (up to date with source v 0.49).
8
9***************************************************************************/
10
11static const UINT8 CX4_immediate_data[48] =
12{
13   0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
14   0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x80, 0xff, 0xff, 0x7f,
15   0x00, 0x80, 0x00, 0xff, 0x7f, 0x00, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0xff,
16   0x00, 0x00, 0x01, 0xff, 0xff, 0xfe, 0x00, 0x01, 0x00, 0xff, 0xfe, 0x00
17};
18
19static const UINT16 CX4_wave_data[40] =
20{
21   0x0000, 0x0002, 0x0004, 0x0006, 0x0008, 0x000a, 0x000c, 0x000e,
22   0x0200, 0x0202, 0x0204, 0x0206, 0x0208, 0x020a, 0x020c, 0x020e,
23   0x0400, 0x0402, 0x0404, 0x0406, 0x0408, 0x040a, 0x040c, 0x040e,
24   0x0600, 0x0602, 0x0604, 0x0606, 0x0608, 0x060a, 0x060c, 0x060e,
25   0x0800, 0x0802, 0x0804, 0x0806, 0x0808, 0x080a, 0x080c, 0x080e
26};
27
28static const UINT32 CX4_sin_table[256] =
29{
30   0x000000, 0x000324, 0x000648, 0x00096c, 0x000c8f, 0x000fb2, 0x0012d5, 0x0015f6,
31   0x001917, 0x001c37, 0x001f56, 0x002273, 0x002590, 0x0028aa, 0x002bc4, 0x002edb,
32   0x0031f1, 0x003505, 0x003817, 0x003b26, 0x003e33, 0x00413e, 0x004447, 0x00474d,
33   0x004a50, 0x004d50, 0x00504d, 0x005347, 0x00563e, 0x005931, 0x005c22, 0x005f0e,
34   0x0061f7, 0x0064dc, 0x0067bd, 0x006a9b, 0x006d74, 0x007049, 0x007319, 0x0075e5,
35   0x0078ad, 0x007b70, 0x007e2e, 0x0080e7, 0x00839c, 0x00864b, 0x0088f5, 0x008b9a,
36   0x008e39, 0x0090d3, 0x009368, 0x0095f6, 0x00987f, 0x009b02, 0x009d7f, 0x009ff6,
37   0x00a267, 0x00a4d2, 0x00a736, 0x00a994, 0x00abeb, 0x00ae3b, 0x00b085, 0x00b2c8,
38   0x00b504, 0x00b73a, 0x00b968, 0x00bb8f, 0x00bdae, 0x00bfc7, 0x00c1d8, 0x00c3e2,
39   0x00c5e4, 0x00c7de, 0x00c9d1, 0x00cbbb, 0x00cd9f, 0x00cf7a, 0x00d14d, 0x00d318,
40   0x00d4db, 0x00d695, 0x00d848, 0x00d9f2, 0x00db94, 0x00dd2d, 0x00debe, 0x00e046,
41   0x00e1c5, 0x00e33c, 0x00e4aa, 0x00e60f, 0x00e76b, 0x00e8bf, 0x00ea09, 0x00eb4b,
42   0x00ec83, 0x00edb2, 0x00eed8, 0x00eff5, 0x00f109, 0x00f213, 0x00f314, 0x00f40b,
43   0x00f4fa, 0x00f5de, 0x00f6ba, 0x00f78b, 0x00f853, 0x00f912, 0x00f9c7, 0x00fa73,
44   0x00fb14, 0x00fbac, 0x00fc3b, 0x00fcbf, 0x00fd3a, 0x00fdab, 0x00fe13, 0x00fe70,
45   0x00fec4, 0x00ff0e, 0x00ff4e, 0x00ff84, 0x00ffb1, 0x00ffd3, 0x00ffec, 0x00fffb,
46   0x000000, 0xfffcdb, 0xfff9b7, 0xfff693, 0xfff370, 0xfff04d, 0xffed2a, 0xffea09,
47   0xffe6e8, 0xffe3c8, 0xffe0a9, 0xffdd8c, 0xffda6f, 0xffd755, 0xffd43b, 0xffd124,
48   0xffce0e, 0xffcafa, 0xffc7e8, 0xffc4d9, 0xffc1cc, 0xffbec1, 0xffbbb8, 0xffb8b2,
49   0xffb5af, 0xffb2af, 0xffafb2, 0xffacb8, 0xffa9c1, 0xffa6ce, 0xffa3dd, 0xffa0f1,
50   0xff9e08, 0xff9b23, 0xff9842, 0xff9564, 0xff928b, 0xff8fb6, 0xff8ce6, 0xff8a1a,
51   0xff8752, 0xff848f, 0xff81d1, 0xff7f18, 0xff7c63, 0xff79b4, 0xff770a, 0xff7465,
52   0xff71c6, 0xff6f2c, 0xff6c97, 0xff6a09, 0xff6780, 0xff64fd, 0xff6280, 0xff6009,
53   0xff5d98, 0xff5b2d, 0xff58c9, 0xff566b, 0xff5414, 0xff51c4, 0xff4f7a, 0xff4d37,
54   0xff4afb, 0xff48c5, 0xff4697, 0xff4470, 0xff4251, 0xff4038, 0xff3e27, 0xff3c1e,
55   0xff3a1b, 0xff3821, 0xff362e, 0xff3444, 0xff3260, 0xff3085, 0xff2eb2, 0xff2ce7,
56   0xff2b24, 0xff296a, 0xff27b7, 0xff260d, 0xff246b, 0xff22d2, 0xff2141, 0xff1fb9,
57   0xff1e3a, 0xff1cc3, 0xff1b55, 0xff19f0, 0xff1894, 0xff1740, 0xff15f6, 0xff14b4,
58   0xff137c, 0xff124d, 0xff1127, 0xff100a, 0xff0ef6, 0xff0dec, 0xff0ceb, 0xff0bf4,
59   0xff0b05, 0xff0a21, 0xff0945, 0xff0874, 0xff07ac, 0xff06ed, 0xff0638, 0xff058d,
60   0xff04eb, 0xff0453, 0xff03c4, 0xff0340, 0xff02c5, 0xff0254, 0xff01ec, 0xff018f,
61   0xff013b, 0xff00f1, 0xff00b1, 0xff007b, 0xff004e, 0xff002c, 0xff0013, 0xff0004
62};
63
64static const INT16 CX4_SinTable[512] =
65{
66         0,   402,    804,   1206,    1607,   2009,   2410,   2811,
67      3211,    3611,   4011,   4409,   4808,   5205,   5602,   5997,
68      6392,    6786,   7179,   7571,   7961,   8351,   8739,   9126,
69      9512,    9896,  10278,  10659,  11039,  11416,  11793,  12167,
70      12539,  12910,  13278,  13645,  14010,  14372,  14732,  15090,
71      15446,  15800,  16151,  16499,  16846,  17189,  17530,  17869,
72      18204,  18537,  18868,  19195,  19519,  19841,  20159,  20475,
73      20787,  21097,  21403,  21706,  22005,  22301,  22594,  22884,
74      23170,  23453,  23732,  24007,  24279,  24547,  24812,  25073,
75      25330,  25583,  25832,  26077,  26319,  26557,  26790,  27020,
76      27245,  27466,  27684,  27897,  28106,  28310,  28511,  28707,
77      28898,  29086,  29269,  29447,  29621,  29791,  29956,  30117,
78      30273,  30425,  30572,  30714,  30852,  30985,  31114,  31237,
79      31357,  31471,  31581,  31685,  31785,  31881,  31971,  32057,
80      32138,  32214,  32285,  32351,  32413,  32469,  32521,  32568,
81      32610,  32647,  32679,  32706,  32728,  32745,  32758,  32765,
82      32767,  32765,  32758,  32745,  32728,  32706,  32679,  32647,
83      32610,  32568,  32521,  32469,  32413,  32351,  32285,  32214,
84      32138,  32057,  31971,  31881,  31785,  31685,  31581,  31471,
85      31357,  31237,  31114,  30985,  30852,  30714,  30572,  30425,
86      30273,  30117,  29956,  29791,  29621,  29447,  29269,  29086,
87      28898,  28707,  28511,  28310,  28106,  27897,  27684,  27466,
88      27245,  27020,  26790,  26557,  26319,  26077,  25832,  25583,
89      25330,  25073,  24812,  24547,  24279,  24007,  23732,  23453,
90      23170,  22884,  22594,  22301,  22005,  21706,  21403,  21097,
91      20787,  20475,  20159,  19841,  19519,  19195,  18868,  18537,
92      18204,  17869,  17530,  17189,  16846,  16499,  16151,  15800,
93      15446,  15090,  14732,  14372,  14010,  13645,  13278,  12910,
94      12539,  12167,  11793,  11416,  11039,  10659,  10278,   9896,
95      9512,    9126,   8739,   8351,   7961,   7571,   7179,   6786,
96      6392,    5997,   5602,   5205,   4808,   4409,   4011,   3611,
97      3211,    2811,   2410,   2009,   1607,   1206,    804,    402,
98         0,   -402,   -804,  -1206,  -1607,  -2009,  -2410,  -2811,
99      -3211,  -3611,  -4011,  -4409,  -4808,  -5205,  -5602,  -5997,
100      -6392,  -6786,  -7179,  -7571,  -7961,  -8351,  -8739,  -9126,
101      -9512,  -9896,  -10278, -10659, -11039, -11416, -11793, -12167,
102   -12539, -12910, -13278, -13645, -14010, -14372, -14732, -15090,
103   -15446, -15800, -16151, -16499, -16846, -17189, -17530, -17869,
104   -18204, -18537, -18868, -19195, -19519, -19841, -20159, -20475,
105   -20787, -21097, -21403, -21706, -22005, -22301, -22594, -22884,
106   -23170, -23453, -23732, -24007, -24279, -24547, -24812, -25073,
107   -25330, -25583, -25832, -26077, -26319, -26557, -26790, -27020,
108   -27245, -27466, -27684, -27897, -28106, -28310, -28511, -28707,
109   -28898, -29086, -29269, -29447, -29621, -29791, -29956, -30117,
110   -30273, -30425, -30572, -30714, -30852, -30985, -31114, -31237,
111   -31357, -31471, -31581, -31685, -31785, -31881, -31971, -32057,
112   -32138, -32214, -32285, -32351, -32413, -32469, -32521, -32568,
113   -32610, -32647, -32679, -32706, -32728, -32745, -32758, -32765,
114   -32767, -32765, -32758, -32745, -32728, -32706, -32679, -32647,
115   -32610, -32568, -32521, -32469, -32413, -32351, -32285, -32214,
116   -32138, -32057, -31971, -31881, -31785, -31685, -31581, -31471,
117   -31357, -31237, -31114, -30985, -30852, -30714, -30572, -30425,
118   -30273, -30117, -29956, -29791, -29621, -29447, -29269, -29086,
119   -28898, -28707, -28511, -28310, -28106, -27897, -27684, -27466,
120   -27245, -27020, -26790, -26557, -26319, -26077, -25832, -25583,
121   -25330, -25073, -24812, -24547, -24279, -24007, -23732, -23453,
122   -23170, -22884, -22594, -22301, -22005, -21706, -21403, -21097,
123   -20787, -20475, -20159, -19841, -19519, -19195, -18868, -18537,
124   -18204, -17869, -17530, -17189, -16846, -16499, -16151, -15800,
125   -15446, -15090, -14732, -14372, -14010, -13645, -13278, -12910,
126   -12539, -12167, -11793, -11416, -11039, -10659, -10278, -9896,
127      -9512,  -9126,  -8739,  -8351,  -7961,  -7571,  -7179,  -6786,
128      -6392,  -5997,  -5602,  -5205,  -4808,  -4409,  -4011,  -3611,
129      -3211,  -2811,  -2410,  -2009,  -1607,  -1206,   -804,   -402
130};
131
132static const INT16 CX4_CosTable[512] =
133{
134      32767,  32765,  32758,  32745,  32728,  32706,  32679,  32647,
135      32610,  32568,  32521,  32469,  32413,  32351,  32285,  32214,
136      32138,  32057,  31971,  31881,  31785,  31685,  31581,  31471,
137      31357,  31237,  31114,  30985,  30852,  30714,  30572,  30425,
138      30273,  30117,  29956,  29791,  29621,  29447,  29269,  29086,
139      28898,  28707,  28511,  28310,  28106,  27897,  27684,  27466,
140      27245,  27020,  26790,  26557,  26319,  26077,  25832,  25583,
141      25330,  25073,  24812,  24547,  24279,  24007,  23732,  23453,
142      23170,  22884,  22594,  22301,  22005,  21706,  21403,  21097,
143      20787,  20475,  20159,  19841,  19519,  19195,  18868,  18537,
144      18204,  17869,  17530,  17189,  16846,  16499,  16151,  15800,
145      15446,  15090,  14732,  14372,  14010,  13645,  13278,  12910,
146      12539,  12167,  11793,  11416,  11039,  10659,  10278,   9896,
147      9512,    9126,   8739,   8351,   7961,   7571,   7179,   6786,
148      6392,    5997,   5602,   5205,   4808,   4409,   4011,   3611,
149      3211,    2811,   2410,   2009,   1607,   1206,    804,    402,
150         0,   -402,   -804,  -1206,  -1607,  -2009,  -2410,  -2811,
151      -3211,  -3611,  -4011,  -4409,  -4808,  -5205,  -5602,  -5997,
152      -6392,  -6786,  -7179,  -7571,  -7961,  -8351,  -8739,  -9126,
153      -9512,  -9896, -10278, -10659, -11039, -11416, -11793, -12167,
154   -12539, -12910, -13278, -13645, -14010, -14372, -14732, -15090,
155   -15446, -15800, -16151, -16499, -16846, -17189, -17530, -17869,
156   -18204, -18537, -18868, -19195, -19519, -19841, -20159, -20475,
157   -20787, -21097, -21403, -21706, -22005, -22301, -22594, -22884,
158   -23170, -23453, -23732, -24007, -24279, -24547, -24812, -25073,
159   -25330, -25583, -25832, -26077, -26319, -26557, -26790, -27020,
160   -27245, -27466, -27684, -27897, -28106, -28310, -28511, -28707,
161   -28898, -29086, -29269, -29447, -29621, -29791, -29956, -30117,
162   -30273, -30425, -30572, -30714, -30852, -30985, -31114, -31237,
163   -31357, -31471, -31581, -31685, -31785, -31881, -31971, -32057,
164   -32138, -32214, -32285, -32351, -32413, -32469, -32521, -32568,
165   -32610, -32647, -32679, -32706, -32728, -32745, -32758, -32765,
166   -32767, -32765, -32758, -32745, -32728, -32706, -32679, -32647,
167   -32610, -32568, -32521, -32469, -32413, -32351, -32285, -32214,
168   -32138, -32057, -31971, -31881, -31785, -31685, -31581, -31471,
169   -31357, -31237, -31114, -30985, -30852, -30714, -30572, -30425,
170   -30273, -30117, -29956, -29791, -29621, -29447, -29269, -29086,
171   -28898, -28707, -28511, -28310, -28106, -27897, -27684, -27466,
172   -27245, -27020, -26790, -26557, -26319, -26077, -25832, -25583,
173   -25330, -25073, -24812, -24547, -24279, -24007, -23732, -23453,
174   -23170, -22884, -22594, -22301, -22005, -21706, -21403, -21097,
175   -20787, -20475, -20159, -19841, -19519, -19195, -18868, -18537,
176   -18204, -17869, -17530, -17189, -16846, -16499, -16151, -15800,
177   -15446, -15090, -14732, -14372, -14010, -13645, -13278, -12910,
178   -12539, -12167, -11793, -11416, -11039, -10659, -10278, -9896,
179      -9512,  -9126,  -8739,  -8351,  -7961,  -7571,  -7179,  -6786,
180      -6392,  -5997,  -5602,  -5205,  -4808,  -4409,  -4011,  -3611,
181      -3211,  -2811,  -2410,  -2009,  -1607,  -1206,   -804,   -402,
182         0,    402,    804,   1206,   1607,   2009,   2410,   2811,
183      3211,    3611,   4011,   4409,   4808,   5205,   5602,   5997,
184      6392,    6786,   7179,   7571,   7961,   8351,   8739,   9126,
185      9512,    9896,  10278,  10659,  11039,  11416,  11793,  12167,
186      12539,  12910,  13278,  13645,  14010,  14372,  14732,  15090,
187      15446,  15800,  16151,  16499,  16846,  17189,  17530,  17869,
188      18204,  18537,  18868,  19195,  19519,  19841,  20159,  20475,
189      20787,  21097,  21403,  21706,  22005,  22301,  22594,  22884,
190      23170,  23453,  23732,  24007,  24279,  24547,  24812,  25073,
191      25330,  25583,  25832,  26077,  26319,  26557,  26790,  27020,
192      27245,  27466,  27684,  27897,  28106,  28310,  28511,  28707,
193      28898,  29086,  29269,  29447,  29621,  29791,  29956,  30117,
194      30273,  30425,  30572,  30714,  30852,  30985,  31114,  31237,
195      31357,  31471,  31581,  31685,  31785,  31881,  31971,  32057,
196      32138,  32214,  32285,  32351,  32413,  32469,  32521,  32568,
197      32610,  32647,  32679,  32706,  32728,  32745,  32758,  32765
198};
trunk/src/mame/machine/snessdd1.c
r21589r21590
1/***************************************************************************
2
3  snessdd1.c
4
5  File to handle emulation of the SNES "S-DD1" add-on chip.
6
7  Based on Andreas Naive Public Domain code.
8
9***************************************************************************/
10
11
12#define SSD1_ADD(addr)\
13mmc[(addr >> 20) & 3] + (addr & 0x0fffff)
14
15class SDD1_IM //Input Manager
16{
17public:
18   SDD1_IM() {}
19
20   UINT32 m_byte_ptr;
21   UINT8 m_bit_count;
22
23   void IM_prepareDecomp(UINT32 in_buf);
24   UINT8 IM_getCodeword(UINT8 *ROM, UINT32 *mmc, const UINT8 code_len);
25};
26
27void SDD1_IM::IM_prepareDecomp(UINT32 in_buf)
28{
29   m_byte_ptr = in_buf;
30   m_bit_count = 4;
31}
32
33UINT8 SDD1_IM::IM_getCodeword(UINT8 *ROM, UINT32 *mmc, const UINT8 code_len)
34{
35   UINT8 codeword = ROM[SSD1_ADD(m_byte_ptr)] << m_bit_count;
36
37   ++m_bit_count;
38
39   if (codeword & 0x80)
40   {
41      codeword |= ROM[SSD1_ADD((m_byte_ptr + 1))] >> (9 - m_bit_count);
42      m_bit_count += code_len;
43   }
44
45   if (m_bit_count & 0x08)
46   {
47      m_byte_ptr++;
48      m_bit_count &= 0x07;
49   }
50
51   return codeword;
52}
53
54class SDD1_GCD //Golomb-Code Decoder
55{
56public:
57   SDD1_GCD(SDD1_IM* associatedIM)
58      : m_IM(associatedIM) { }
59
60   SDD1_IM* m_IM;
61
62   void GCD_getRunCount(UINT8 *ROM, UINT32 *mmc, UINT8 code_num, UINT8* MPScount, UINT8* LPSind);
63};
64
65void SDD1_GCD::GCD_getRunCount(UINT8 *ROM, UINT32 *mmc, UINT8 code_num, UINT8* MPScount, UINT8* LPSind)
66{
67   const UINT8 run_count[] =
68   {
69      0x00, 0x00, 0x01, 0x00, 0x03, 0x01, 0x02, 0x00,
70      0x07, 0x03, 0x05, 0x01, 0x06, 0x02, 0x04, 0x00,
71      0x0f, 0x07, 0x0b, 0x03, 0x0d, 0x05, 0x09, 0x01,
72      0x0e, 0x06, 0x0a, 0x02, 0x0c, 0x04, 0x08, 0x00,
73      0x1f, 0x0f, 0x17, 0x07, 0x1b, 0x0b, 0x13, 0x03,
74      0x1d, 0x0d, 0x15, 0x05, 0x19, 0x09, 0x11, 0x01,
75      0x1e, 0x0e, 0x16, 0x06, 0x1a, 0x0a, 0x12, 0x02,
76      0x1c, 0x0c, 0x14, 0x04, 0x18, 0x08, 0x10, 0x00,
77      0x3f, 0x1f, 0x2f, 0x0f, 0x37, 0x17, 0x27, 0x07,
78      0x3b, 0x1b, 0x2b, 0x0b, 0x33, 0x13, 0x23, 0x03,
79      0x3d, 0x1d, 0x2d, 0x0d, 0x35, 0x15, 0x25, 0x05,
80      0x39, 0x19, 0x29, 0x09, 0x31, 0x11, 0x21, 0x01,
81      0x3e, 0x1e, 0x2e, 0x0e, 0x36, 0x16, 0x26, 0x06,
82      0x3a, 0x1a, 0x2a, 0x0a, 0x32, 0x12, 0x22, 0x02,
83      0x3c, 0x1c, 0x2c, 0x0c, 0x34, 0x14, 0x24, 0x04,
84      0x38, 0x18, 0x28, 0x08, 0x30, 0x10, 0x20, 0x00,
85      0x7f, 0x3f, 0x5f, 0x1f, 0x6f, 0x2f, 0x4f, 0x0f,
86      0x77, 0x37, 0x57, 0x17, 0x67, 0x27, 0x47, 0x07,
87      0x7b, 0x3b, 0x5b, 0x1b, 0x6b, 0x2b, 0x4b, 0x0b,
88      0x73, 0x33, 0x53, 0x13, 0x63, 0x23, 0x43, 0x03,
89      0x7d, 0x3d, 0x5d, 0x1d, 0x6d, 0x2d, 0x4d, 0x0d,
90      0x75, 0x35, 0x55, 0x15, 0x65, 0x25, 0x45, 0x05,
91      0x79, 0x39, 0x59, 0x19, 0x69, 0x29, 0x49, 0x09,
92      0x71, 0x31, 0x51, 0x11, 0x61, 0x21, 0x41, 0x01,
93      0x7e, 0x3e, 0x5e, 0x1e, 0x6e, 0x2e, 0x4e, 0x0e,
94      0x76, 0x36, 0x56, 0x16, 0x66, 0x26, 0x46, 0x06,
95      0x7a, 0x3a, 0x5a, 0x1a, 0x6a, 0x2a, 0x4a, 0x0a,
96      0x72, 0x32, 0x52, 0x12, 0x62, 0x22, 0x42, 0x02,
97      0x7c, 0x3c, 0x5c, 0x1c, 0x6c, 0x2c, 0x4c, 0x0c,
98      0x74, 0x34, 0x54, 0x14, 0x64, 0x24, 0x44, 0x04,
99      0x78, 0x38, 0x58, 0x18, 0x68, 0x28, 0x48, 0x08,
100      0x70, 0x30, 0x50, 0x10, 0x60, 0x20, 0x40, 0x00,
101   };
102
103   UINT8 codeword = m_IM->IM_getCodeword(ROM, mmc, code_num);
104
105   if (codeword & 0x80)
106   {
107      *LPSind = 1;
108      *MPScount = run_count[codeword >> (code_num ^ 0x07)];
109   }
110   else
111   {
112      *MPScount = (1 << code_num);
113   }
114}
115
116class SDD1_BG // Bits Generator
117{
118public:
119   SDD1_BG(SDD1_GCD* associatedGCD, UINT8 code)
120      : m_code_num(code),
121         m_GCD(associatedGCD) { }
122
123   UINT8 m_code_num;
124   UINT8 m_MPScount;
125   UINT8 m_LPSind;
126   SDD1_GCD* m_GCD;
127
128   void BG_prepareDecomp();
129   UINT8 BG_getBit(UINT8 *ROM, UINT32 *mmc, UINT8* endOfRun);
130} ;
131
132void SDD1_BG::BG_prepareDecomp()
133{
134   m_MPScount = 0;
135   m_LPSind = 0;
136}
137
138UINT8 SDD1_BG::BG_getBit(UINT8 *ROM, UINT32 *mmc, UINT8* endOfRun)
139{
140   UINT8 bit;
141
142   if (!(m_MPScount || m_LPSind))
143   {
144      m_GCD->GCD_getRunCount(ROM, mmc, m_code_num, &(m_MPScount), &(m_LPSind));
145   }
146
147   if (m_MPScount)
148   {
149      bit = 0;
150      m_MPScount--;
151   }
152   else
153   {
154      bit = 1;
155      m_LPSind = 0;
156   }
157
158   if (m_MPScount || m_LPSind)
159   {
160      (*endOfRun) = 0;
161   }
162   else
163   {
164      (*endOfRun) = 1;
165   }
166
167   return bit;
168}
169
170
171struct SDD1_PEM_state
172{
173   UINT8 code_num;
174   UINT8 nextIfMPS;
175   UINT8 nextIfLPS;
176};
177
178static const SDD1_PEM_state PEM_evolution_table[33] =
179{
180   { 0,25,25},
181   { 0, 2, 1},
182   { 0, 3, 1},
183   { 0, 4, 2},
184   { 0, 5, 3},
185   { 1, 6, 4},
186   { 1, 7, 5},
187   { 1, 8, 6},
188   { 1, 9, 7},
189   { 2,10, 8},
190   { 2,11, 9},
191   { 2,12,10},
192   { 2,13,11},
193   { 3,14,12},
194   { 3,15,13},
195   { 3,16,14},
196   { 3,17,15},
197   { 4,18,16},
198   { 4,19,17},
199   { 5,20,18},
200   { 5,21,19},
201   { 6,22,20},
202   { 6,23,21},
203   { 7,24,22},
204   { 7,24,23},
205   { 0,26, 1},
206   { 1,27, 2},
207   { 2,28, 4},
208   { 3,29, 8},
209   { 4,30,12},
210   { 5,31,16},
211   { 6,32,18},
212   { 7,24,22}
213};
214
215struct SDD1_PEM_ContextInfo
216{
217   UINT8 status;
218   UINT8 MPS;
219};
220
221class SDD1_PEM //Probability Estimation Module
222{
223public:
224   SDD1_PEM(
225         SDD1_BG* associatedBG0, SDD1_BG* associatedBG1,
226         SDD1_BG* associatedBG2, SDD1_BG* associatedBG3,
227         SDD1_BG* associatedBG4, SDD1_BG* associatedBG5,
228         SDD1_BG* associatedBG6, SDD1_BG* associatedBG7)
229   {
230      m_BG[0] = associatedBG0;
231      m_BG[1] = associatedBG1;
232      m_BG[2] = associatedBG2;
233      m_BG[3] = associatedBG3;
234      m_BG[4] = associatedBG4;
235      m_BG[5] = associatedBG5;
236      m_BG[6] = associatedBG6;
237      m_BG[7] = associatedBG7;
238   }
239
240   SDD1_PEM_ContextInfo m_contextInfo[32];
241   SDD1_BG* m_BG[8];
242
243   void PEM_prepareDecomp();
244   UINT8 PEM_getBit(UINT8 *ROM, UINT32 *mmc, UINT8 context);
245} ;
246
247void SDD1_PEM::PEM_prepareDecomp()
248{
249   for (int i = 0; i < 32; i++)
250   {
251      m_contextInfo[i].status = 0;
252      m_contextInfo[i].MPS = 0;
253   }
254}
255
256UINT8 SDD1_PEM::PEM_getBit(UINT8 *ROM, UINT32 *mmc, UINT8 context)
257{
258   UINT8 endOfRun;
259   UINT8 bit;
260
261   SDD1_PEM_ContextInfo *pContInfo = &(m_contextInfo)[context];
262   UINT8 currStatus = pContInfo->status;
263   const SDD1_PEM_state* pState = &(PEM_evolution_table[currStatus]);
264   UINT8 currentMPS = pContInfo->MPS;
265
266   bit = m_BG[pState->code_num]->BG_getBit(ROM, mmc, &endOfRun);
267
268   if (endOfRun)
269   {
270      if (bit)
271      {
272         if (!(currStatus & 0xfe))
273         {
274            (pContInfo->MPS) ^= 0x01;
275         }
276         pContInfo->status = pState->nextIfLPS;
277      }
278      else
279      {
280         pContInfo->status = pState->nextIfMPS;
281      }
282   }
283
284   return bit ^ currentMPS;
285}
286
287class SDD1_CM
288{
289public:
290   SDD1_CM(SDD1_PEM* associatedPEM)
291      : m_PEM(associatedPEM) { }
292
293   UINT8 m_bitplanesInfo;
294   UINT8 m_contextBitsInfo;
295   UINT8 m_bit_number;
296   UINT8 m_currBitplane;
297   UINT16 m_prevBitplaneBits[8];
298   SDD1_PEM* m_PEM;
299
300   void CM_prepareDecomp(UINT8 *ROM, UINT32 *mmc, UINT32 first_byte);
301   UINT8 CM_getBit(UINT8 *ROM, UINT32 *mmc);
302} ;
303
304void SDD1_CM::CM_prepareDecomp(UINT8 *ROM, UINT32 *mmc, UINT32 first_byte)
305{
306   INT32 i = 0;
307   m_bitplanesInfo = ROM[SSD1_ADD(first_byte)] & 0xc0;
308   m_contextBitsInfo = ROM[SSD1_ADD(first_byte)] & 0x30;
309   m_bit_number = 0;
310   for (i = 0; i < 8; i++)
311   {
312      m_prevBitplaneBits[i] = 0;
313   }
314   switch (m_bitplanesInfo)
315   {
316      case 0x00:
317         m_currBitplane = 1;
318         break;
319      case 0x40:
320         m_currBitplane = 7;
321         break;
322      case 0x80:
323         m_currBitplane = 3;
324         break;
325   }
326}
327
328UINT8 SDD1_CM::CM_getBit(UINT8 *ROM, UINT32 *mmc)
329{
330   UINT8 currContext;
331   UINT16 *context_bits;
332   UINT8 bit = 0;
333
334   switch (m_bitplanesInfo)
335   {
336      case 0x00:
337         m_currBitplane ^= 0x01;
338         break;
339      case 0x40:
340         m_currBitplane ^= 0x01;
341         if (!(m_bit_number & 0x7f))
342            m_currBitplane = ((m_currBitplane + 2) & 0x07);
343         break;
344      case 0x80:
345         m_currBitplane ^= 0x01;
346         if (!(m_bit_number & 0x7f))
347            m_currBitplane ^= 0x02;
348         break;
349      case 0xc0:
350         m_currBitplane = m_bit_number & 0x07;
351         break;
352   }
353
354   context_bits = &(m_prevBitplaneBits)[m_currBitplane];
355
356   currContext = (m_currBitplane & 0x01) << 4;
357   switch (m_contextBitsInfo)
358   {
359      case 0x00:
360         currContext |= ((*context_bits & 0x01c0) >> 5) | (*context_bits & 0x0001);
361         break;
362      case 0x10:
363         currContext |= ((*context_bits & 0x0180) >> 5) | (*context_bits & 0x0001);
364         break;
365      case 0x20:
366         currContext |= ((*context_bits & 0x00c0) >> 5) | (*context_bits & 0x0001);
367         break;
368      case 0x30:
369         currContext |= ((*context_bits & 0x0180) >> 5) | (*context_bits & 0x0003);
370         break;
371   }
372
373   bit = m_PEM->PEM_getBit(ROM, mmc, currContext);
374
375   *context_bits <<= 1;
376   *context_bits |= bit;
377
378   m_bit_number++;
379
380   return bit;
381}
382
383class SDD1_OL
384{
385public:
386   SDD1_OL(SDD1_CM* associatedCM)
387      : m_CM(associatedCM) { }
388
389   UINT8 m_bitplanesInfo;
390   UINT16 m_length;
391   UINT8* m_buffer;
392   SDD1_CM* m_CM;
393
394   void OL_prepareDecomp(UINT8 *ROM, UINT32 *mmc, UINT32 first_byte, UINT16 out_len, UINT8 *out_buf);
395   void OL_launch(UINT8 *ROM, UINT32 *mmc);
396} ;
397
398void SDD1_OL::OL_prepareDecomp(UINT8 *ROM, UINT32 *mmc, UINT32 first_byte, UINT16 out_len, UINT8 *out_buf)
399{
400   m_bitplanesInfo = ROM[SSD1_ADD(first_byte)] & 0xc0;
401   m_length = out_len;
402   m_buffer = out_buf;
403}
404
405void SDD1_OL::OL_launch(UINT8 *ROM, UINT32 *mmc)
406{
407   UINT8 i;
408   UINT8 register1 = 0, register2 = 0;
409
410   switch (m_bitplanesInfo)
411   {
412      case 0x00:
413      case 0x40:
414      case 0x80:
415         i = 1;
416         do
417         {   // if length == 0, we output 2^16 bytes
418            if (!i)
419            {
420               *(m_buffer++) = register2;
421               i = ~i;
422            }
423            else
424            {
425               for (register1 = register2 = 0, i = 0x80; i; i >>= 1)
426               {
427                  if (m_CM->CM_getBit(ROM, mmc))
428                     register1 |= i;
429
430                  if (m_CM->CM_getBit(ROM, mmc))
431                     register2 |= i;
432               }
433               *(m_buffer++) = register1;
434            }
435         } while (--(m_length));
436         break;
437      case 0xc0:
438         do
439         {
440            for (register1 = 0, i = 0x01; i; i <<= 1)
441            {
442               if (m_CM->CM_getBit(ROM, mmc))
443               {
444                  register1 |= i;
445               }
446            }
447            *(m_buffer++) = register1;
448         } while (--(m_length));
449         break;
450   }
451}
452
453class SDD1emu
454{
455public:
456   SDD1emu(running_machine &machine);
457
458   running_machine &machine() const { return m_machine; }
459
460   SDD1_IM* m_IM;
461   SDD1_GCD* m_GCD;
462   SDD1_BG* m_BG0;   SDD1_BG* m_BG1;   SDD1_BG* m_BG2;   SDD1_BG* m_BG3;
463   SDD1_BG* m_BG4;   SDD1_BG* m_BG5;   SDD1_BG* m_BG6;   SDD1_BG* m_BG7;
464   SDD1_PEM* m_PEM;
465   SDD1_CM* m_CM;
466   SDD1_OL* m_OL;
467
468   void SDD1emu_decompress(UINT8 *ROM, UINT32 *mmc, UINT32 in_buf, UINT16 out_len, UINT8 *out_buf);
469
470private:
471   running_machine& m_machine;
472};
473
474SDD1emu::SDD1emu(running_machine &machine)
475   : m_machine(machine)
476{
477   m_IM = auto_alloc(machine, SDD1_IM());
478   m_GCD = auto_alloc(machine, SDD1_GCD(m_IM));
479   m_BG0 = auto_alloc(machine, SDD1_BG(m_GCD, 0));
480   m_BG1 = auto_alloc(machine, SDD1_BG(m_GCD, 1));
481   m_BG2 = auto_alloc(machine, SDD1_BG(m_GCD, 2));
482   m_BG3 = auto_alloc(machine, SDD1_BG(m_GCD, 3));
483   m_BG4 = auto_alloc(machine, SDD1_BG(m_GCD, 4));
484   m_BG5 = auto_alloc(machine, SDD1_BG(m_GCD, 5));
485   m_BG6 = auto_alloc(machine, SDD1_BG(m_GCD, 6));
486   m_BG7 = auto_alloc(machine, SDD1_BG(m_GCD, 7));
487   m_PEM = auto_alloc(machine, SDD1_PEM(m_BG0, m_BG1, m_BG2, m_BG3,
488                                 m_BG4, m_BG5, m_BG6, m_BG7));
489   m_CM = auto_alloc(machine, SDD1_CM(m_PEM));
490   m_OL = auto_alloc(machine, SDD1_OL(m_CM));
491}
492
493void SDD1emu::SDD1emu_decompress(UINT8 *ROM, UINT32 *mmc, UINT32 in_buf, UINT16 out_len, UINT8 *out_buf)
494{
495   m_IM->IM_prepareDecomp(in_buf);
496   m_BG0->BG_prepareDecomp();
497   m_BG1->BG_prepareDecomp();
498   m_BG2->BG_prepareDecomp();
499   m_BG3->BG_prepareDecomp();
500   m_BG4->BG_prepareDecomp();
501   m_BG5->BG_prepareDecomp();
502   m_BG6->BG_prepareDecomp();
503   m_BG7->BG_prepareDecomp();
504   m_PEM->PEM_prepareDecomp();
505   m_CM->CM_prepareDecomp(ROM, mmc, in_buf);
506   m_OL->OL_prepareDecomp(ROM, mmc, in_buf, out_len, out_buf);
507
508   m_OL->OL_launch(ROM, mmc);
509}
510
511struct snes_sdd1_t
512{
513   UINT8 sdd1_enable;  // channel bit-mask
514   UINT8 xfer_enable;  // channel bit-mask
515   UINT32 mmc[4];      // memory map controller ROM indices
516
517   struct
518   {
519      UINT32 addr;    // $43x2-$43x4 -- DMA transfer address
520      UINT16 size;    // $43x5-$43x6 -- DMA transfer size
521   } dma[8];
522
523   SDD1emu* sdd1emu;
524   struct
525   {
526      UINT8 *data;    // pointer to decompressed S-DD1 data (65536 bytes)
527      UINT16 offset;  // read index into S-DD1 decompression buffer
528      UINT32 size;    // length of data buffer; reads decrement counter, set ready to false at 0
529      UINT8 ready;    // 1 when data[] is valid; 0 to invoke sdd1emu.decompress()
530   } buffer;
531} ;
532
533static snes_sdd1_t snes_sdd1;
534
535void sdd1_init(running_machine& machine)
536{
537   snes_sdd1.sdd1_enable = 0x00;
538   snes_sdd1.xfer_enable = 0x00;
539
540   snes_sdd1.mmc[0] = 0 << 20;
541   snes_sdd1.mmc[1] = 1 << 20;
542   snes_sdd1.mmc[2] = 2 << 20;
543   snes_sdd1.mmc[3] = 3 << 20;
544
545   for (int i = 0; i < 8; i++)
546   {
547      snes_sdd1.dma[i].addr = 0;
548      snes_sdd1.dma[i].size = 0;
549   }
550
551   snes_sdd1.sdd1emu = auto_alloc(machine, SDD1emu(machine));
552
553   snes_sdd1.buffer.data = (UINT8*)auto_alloc_array(machine, UINT8, 0x10000);
554   snes_sdd1.buffer.ready = 0;
555}
556
557UINT8 sdd1_mmio_read(address_space &space, UINT32 addr)
558{
559   addr &= 0xffff;
560
561   switch(addr)
562   {
563      case 0x4804:
564         return (snes_sdd1.mmc[0] >> 20) & 7;
565      case 0x4805:
566         return (snes_sdd1.mmc[1] >> 20) & 7;
567      case 0x4806:
568         return (snes_sdd1.mmc[2] >> 20) & 7;
569      case 0x4807:
570         return (snes_sdd1.mmc[3] >> 20) & 7;
571   }
572
573   return snes_open_bus_r(space, 0);
574}
575
576void sdd1_mmio_write(address_space &space, UINT32 addr, UINT8 data)
577{
578   addr &= 0xffff;
579
580   if ((addr & 0x4380) == 0x4300)
581   {
582      UINT8 channel = (addr >> 4) & 7;
583      switch(addr & 15)
584      {
585         case 2:
586            snes_sdd1.dma[channel].addr = (snes_sdd1.dma[channel].addr & 0xffff00) + (data <<  0);
587            break;
588         case 3:
589            snes_sdd1.dma[channel].addr = (snes_sdd1.dma[channel].addr & 0xff00ff) + (data <<  8);
590            break;
591         case 4:
592            snes_sdd1.dma[channel].addr = (snes_sdd1.dma[channel].addr & 0x00ffff) + (data << 16);
593            break;
594
595         case 5:
596            snes_sdd1.dma[channel].size = (snes_sdd1.dma[channel].size &   0xff00) + (data <<  0);
597            break;
598         case 6:
599            snes_sdd1.dma[channel].size = (snes_sdd1.dma[channel].size &   0x00ff) + (data <<  8);
600            break;
601      }
602      return;
603   }
604
605   switch(addr)
606   {
607      case 0x4800:
608         snes_sdd1.sdd1_enable = data;
609         break;
610      case 0x4801:
611         snes_sdd1.xfer_enable = data;
612         break;
613
614      case 0x4804:
615         snes_sdd1.mmc[0] = (data & 7) << 20;
616         break;
617      case 0x4805:
618         snes_sdd1.mmc[1] = (data & 7) << 20;
619         break;
620      case 0x4806:
621         snes_sdd1.mmc[2] = (data & 7) << 20;
622         break;
623      case 0x4807:
624         snes_sdd1.mmc[3] = (data & 7) << 20;
625         break;
626   }
627}
628
629UINT8 sdd1_read(running_machine& machine, UINT32 addr)
630{
631   unsigned char *ROM = machine.root_device().memregion("cart")->base();
632
633   if (snes_sdd1.sdd1_enable & snes_sdd1.xfer_enable)
634   {
635      // at least one channel has S-DD1 decompression enabled...
636      for (int i = 0; i < 8; i++)
637      {
638         if (snes_sdd1.sdd1_enable & snes_sdd1.xfer_enable & (1 << i))
639         {
640            // S-DD1 always uses fixed transfer mode, so address will not change during transfer
641            if ((addr + 0xc00000) == snes_sdd1.dma[i].addr)
642            {
643               UINT8 data;
644               if (!snes_sdd1.buffer.ready)
645               {
646                  UINT8 temp;
647                  // first byte read for channel performs full decompression.
648                  // this really should stream byte-by-byte, but it's not necessary since the size is known
649                  snes_sdd1.buffer.offset = 0;
650                  snes_sdd1.buffer.size = snes_sdd1.dma[i].size ? snes_sdd1.dma[i].size : 65536;
651
652                  // sdd1emu calls this function; it needs to access uncompressed data;
653                  // so temporarily disable decompression mode for decompress() call.
654                  temp = snes_sdd1.sdd1_enable;
655                  snes_sdd1.sdd1_enable = 0;
656                  snes_sdd1.sdd1emu->SDD1emu_decompress(ROM, snes_sdd1.mmc, addr, snes_sdd1.buffer.size, snes_sdd1.buffer.data);
657                  snes_sdd1.sdd1_enable = temp;
658
659                  snes_sdd1.buffer.ready = 1;
660               }
661
662               // fetch a decompressed byte; once buffer is depleted, disable channel and invalidate buffer
663               data = snes_sdd1.buffer.data[(UINT16)snes_sdd1.buffer.offset++];
664               if (snes_sdd1.buffer.offset >= snes_sdd1.buffer.size)
665               {
666                  snes_sdd1.buffer.ready = 0;
667                  snes_sdd1.xfer_enable &= ~(1 << i);
668               }
669
670               return data;
671            } // address matched
672         } // channel enabled
673      } // channel loop
674   } // S-DD1 decompressor enabled
675
676   return ROM[snes_sdd1.mmc[(addr >> 20) & 3] + (addr & 0x0fffff)];
677}
trunk/src/mame/machine/cx4oam.c
r21589r21590
1/***************************************************************************
2
3    cx4oam.c
4
5    Code based on original work by zsKnight, anomie and Nach.
6    This implementation is based on C++ "cx4*.cpp" by byuu
7    (up to date with source v 0.49).
8
9***************************************************************************/
10
11//Build OAM
12static void CX4_op00_00(running_machine &machine)
13{
14   INT32 i;
15
16   UINT32 oamptr = cx4.ram[0x626] << 2;
17   UINT16 globalx, globaly;
18   UINT32 oamptr2;
19   INT16 sprx, spry;
20   UINT8 sprname, sprattr;
21   UINT8 sprcount;
22   UINT8 offset;
23   UINT32 srcptr;
24
25   for(i = 0x1fd; i > oamptr && i >= 0; i -= 4)
26   {
27      //clear oam-to-be
28      if(i >= 0)
29      {
30         cx4.ram[i] = 0xe0;
31      }
32   }
33
34   globalx = CX4_readw(0x621);
35   globaly = CX4_readw(0x623);
36   oamptr2 = 0x200 + (cx4.ram[0x626] >> 2);
37
38   if(!cx4.ram[0x620])
39   {
40      return;
41   }
42
43   sprcount = 128 - cx4.ram[0x626];
44   offset = (cx4.ram[0x626] & 3) * 2;
45   srcptr = 0x220;
46
47   address_space &space = machine.device<cpu_device>("maincpu")->space(AS_PROGRAM);
48   for(i = cx4.ram[0x620]; i > 0 && sprcount > 0; i--, srcptr += 16)
49   {
50      UINT32 spraddr = CX4_readl(srcptr + 7);
51
52      sprx = CX4_readw(srcptr)     - globalx;
53      spry = CX4_readw(srcptr + 2) - globaly;
54      sprname = cx4.ram[srcptr + 5];
55      sprattr = cx4.ram[srcptr + 4] | cx4.ram[srcptr + 6];
56
57      if(space.read_byte(spraddr))
58      {
59         INT16 x, y;
60         INT32 sprcnt;
61         for(sprcnt = space.read_byte(spraddr++); sprcnt > 0 && sprcount > 0; sprcnt--, spraddr += 4)
62         {
63            x = (INT8)space.read_byte(spraddr + 1);
64            if(sprattr & 0x40)
65            {
66               x = -x - ((space.read_byte(spraddr) & 0x20) ? 16 : 8);
67            }
68            x += sprx;
69            if(x >= -16 && x <= 272)
70            {
71               y = (INT8)space.read_byte(spraddr + 2);
72               if(sprattr & 0x80)
73               {
74                  y = -y - ((space.read_byte(spraddr) & 0x20) ? 16 : 8);
75               }
76               y += spry;
77               if(y >= -16 && y <= 224)
78               {
79                  cx4.ram[oamptr    ] = (UINT8)x;
80                  cx4.ram[oamptr + 1] = (UINT8)y;
81                  cx4.ram[oamptr + 2] = sprname + space.read_byte(spraddr + 3);
82                  cx4.ram[oamptr + 3] = sprattr ^ (space.read_byte(spraddr) & 0xc0);
83                  cx4.ram[oamptr2] &= ~(3 << offset);
84                  if(x & 0x100)
85                  {
86                     cx4.ram[oamptr2] |= 1 << offset;
87                  }
88                  if(space.read_byte(spraddr) & 0x20)
89                  {
90                     cx4.ram[oamptr2] |= 2 << offset;
91                  }
92                  oamptr += 4;
93                  sprcount--;
94                  offset = (offset + 2) & 6;
95                  if(!offset)
96                  {
97                     oamptr2++;
98                  }
99               }
100            }
101         }
102      }
103      else if(sprcount > 0)
104      {
105         cx4.ram[oamptr    ] = (UINT8)sprx;
106         cx4.ram[oamptr + 1] = (UINT8)spry;
107         cx4.ram[oamptr + 2] = sprname;
108         cx4.ram[oamptr + 3] = sprattr;
109         cx4.ram[oamptr2] &= ~(3 << offset);
110         if(sprx & 0x100)
111         {
112            cx4.ram[oamptr2] |= 3 << offset;
113         }
114         else
115         {
116            cx4.ram[oamptr2] |= 2 << offset;
117         }
118         oamptr += 4;
119         sprcount--;
120         offset = (offset + 2) & 6;
121         if(!offset)
122         {
123            oamptr2++;
124         }
125      }
126   }
127}
128
129//Scale and Rotate
130static void CX4_op00_03(void)
131{
132   CX4_C4DoScaleRotate(0);
133}
134
135//Transform Lines
136static void CX4_op00_05(running_machine &machine)
137{
138   INT32 i;
139   UINT32 ptr = 0, ptr2 = 0;
140
141   cx4.C4WFX2Val = CX4_read(0x1f83);
142   cx4.C4WFY2Val = CX4_read(0x1f86);
143   cx4.C4WFDist  = CX4_read(0x1f89);
144   cx4.C4WFScale = CX4_read(0x1f8c);
145
146   //Transform Vertices
147   for(i = CX4_readw(0x1f80); i > 0; i--, ptr += 0x10)
148   {
149      cx4.C4WFXVal = CX4_readw(ptr + 1);
150      cx4.C4WFYVal = CX4_readw(ptr + 5);
151      cx4.C4WFZVal = CX4_readw(ptr + 9);
152      CX4_C4TransfWireFrame();
153
154      //Displace
155      CX4_writew(machine, ptr + 1, cx4.C4WFXVal + 0x80);
156      CX4_writew(machine, ptr + 5, cx4.C4WFYVal + 0x50);
157   }
158
159   CX4_writew(machine, 0x600,     23);
160   CX4_writew(machine, 0x602,     0x60);
161   CX4_writew(machine, 0x605,     0x40);
162   CX4_writew(machine, 0x600 + 8, 23);
163   CX4_writew(machine, 0x602 + 8, 0x60);
164   CX4_writew(machine, 0x605 + 8, 0x40);
165
166   ptr = 0xb02;
167
168   for(i = CX4_readw(0xb00); i > 0; i--, ptr += 2, ptr2 += 8)
169   {
170      cx4.C4WFXVal  = CX4_readw((CX4_read(ptr + 0) << 4) + 1);
171      cx4.C4WFYVal  = CX4_readw((CX4_read(ptr + 0) << 4) + 5);
172      cx4.C4WFX2Val = CX4_readw((CX4_read(ptr + 1) << 4) + 1);
173      cx4.C4WFY2Val = CX4_readw((CX4_read(ptr + 1) << 4) + 5);
174      CX4_C4CalcWireFrame();
175      CX4_writew(machine, ptr2 + 0x600, cx4.C4WFDist ? cx4.C4WFDist : 1);
176      CX4_writew(machine, ptr2 + 0x602, cx4.C4WFXVal);
177      CX4_writew(machine, ptr2 + 0x605, cx4.C4WFYVal);
178   }
179}
180
181//Scale and Rotate
182static void CX4_op00_07(void)
183{
184   CX4_C4DoScaleRotate(64);
185}
186
187//Draw Wireframe
188static void CX4_op00_08(running_machine &machine)
189{
190   CX4_C4DrawWireFrame(machine);
191}
192
193//Disintegrate
194static void CX4_op00_0b(running_machine &machine)
195{
196   UINT8  width, height;
197   UINT32 startx, starty;
198   UINT32 srcptr;
199   UINT32 x, y;
200   INT32  scalex, scaley;
201   INT32  cx, cy;
202   INT32  i, j;
203
204   width  = CX4_read(0x1f89);
205   height = CX4_read(0x1f8c);
206   cx     = CX4_readw(0x1f80);
207   cy     = CX4_readw(0x1f83);
208
209   scalex = (INT16)CX4_readw(0x1f86);
210   scaley = (INT16)CX4_readw(0x1f8f);
211   startx = -cx * scalex + (cx << 8);
212   starty = -cy * scaley + (cy << 8);
213   srcptr = 0x600;
214
215   for(i = 0; i < (width * height) >> 1; i++)
216   {
217      CX4_write(machine, i, 0);
218   }
219
220   for(y = starty, i = 0;i < height; i++, y += scaley)
221   {
222      for(x = startx, j = 0;j < width; j++, x += scalex)
223      {
224         if((x >> 8) < width && (y >> 8) < height && (y >> 8) * width + (x >> 8) < 0x2000)
225         {
226            UINT8 pixel = (j & 1) ? (cx4.ram[srcptr] >> 4) : (cx4.ram[srcptr]);
227            INT32 index = (y >> 11) * width * 4 + (x >> 11) * 32 + ((y >> 8) & 7) * 2;
228            UINT8 mask = 0x80 >> ((x >> 8) & 7);
229
230            if(pixel & 1) cx4.ram[index     ] |= mask;
231            if(pixel & 2) cx4.ram[index +  1] |= mask;
232            if(pixel & 4) cx4.ram[index + 16] |= mask;
233            if(pixel & 8) cx4.ram[index + 17] |= mask;
234         }
235         if(j & 1)
236         {
237            srcptr++;
238         }
239      }
240   }
241}
242
243//Bitplane Wave
244static void CX4_op00_0c(running_machine &machine)
245{
246   int i, j;
247   UINT32 destptr = 0;
248   UINT32 waveptr = CX4_read(0x1f83);
249   UINT16 mask1   = 0xc0c0;
250   UINT16 mask2   = 0x3f3f;
251
252   for(j = 0; j < 0x10; j++)
253   {
254      do
255      {
256         INT16 height = -((INT8)CX4_read(waveptr + 0xb00)) - 16;
257         for(i = 0; i < 40; i++)
258         {
259            UINT16 temp = CX4_readw(destptr + CX4_wave_data[i]) & mask2;
260            if(height >= 0)
261            {
262               if(height < 8)
263               {
264                  temp |= mask1 & CX4_readw(0xa00 + height * 2);
265               }
266               else
267               {
268                  temp |= mask1 & 0xff00;
269               }
270            }
271            CX4_writew(machine, destptr + CX4_wave_data[i], temp);
272            height++;
273         }
274         waveptr = (waveptr + 1) & 0x7f;
275         mask1   = (mask1 >> 2) | (mask1 << 6);
276         mask2   = (mask2 >> 2) | (mask2 << 6);
277      } while(mask1 != 0xc0c0);
278      destptr += 16;
279
280      do
281      {
282         INT16 height = -((INT8)CX4_read(waveptr + 0xb00)) - 16;
283         for(i = 0; i < 40; i++)
284         {
285            UINT16 temp = CX4_readw(destptr + CX4_wave_data[i]) & mask2;
286            if(height >= 0)
287            {
288               if(height < 8)
289               {
290                  temp |= mask1 & CX4_readw(0xa10 + height * 2);
291               }
292               else
293               {
294                  temp |= mask1 & 0xff00;
295               }
296            }
297            CX4_writew(machine, destptr + CX4_wave_data[i], temp);
298            height++;
299         }
300         waveptr = (waveptr + 1) & 0x7f;
301         mask1   = (mask1 >> 2) | (mask1 << 6);
302         mask2   = (mask2 >> 2) | (mask2 << 6);
303      } while(mask1 != 0xc0c0);
304      destptr += 16;
305   }
306}
trunk/src/mame/machine/snesobc1.c
r21589r21590
1/***************************************************************************
2
3  snesobc1.c
4
5  File to handle emulation of the SNES "OBC-1" add-on chip.
6
7  Original C++ code by byuu.
8  Byuu's code is released under GNU General Public License
9  version 2 as published by the Free Software Foundation.
10  The implementation below is released under the MAME license
11  for use in MAME, MESS and derivatives by permission of the author.
12
13***************************************************************************/
14
15struct snes_obc1_state
16{
17   int address;
18   int offset;
19   int shift;
20};
21
22static snes_obc1_state obc1_state;
23
24
25READ8_HANDLER( obc1_read )
26{
27   UINT16 address = offset & 0x1fff;
28   UINT8 value;
29
30   switch (address)
31   {
32      case 0x1ff0:
33         value = snes_ram[obc1_state.offset + (obc1_state.address << 2) + 0];
34         break;
35
36      case 0x1ff1:
37         value = snes_ram[obc1_state.offset + (obc1_state.address << 2) + 1];
38         break;
39
40      case 0x1ff2:
41         value = snes_ram[obc1_state.offset + (obc1_state.address << 2) + 2];
42         break;
43
44      case 0x1ff3:
45         value = snes_ram[obc1_state.offset + (obc1_state.address << 2) + 3];
46         break;
47
48      case 0x1ff4:
49         value = snes_ram[obc1_state.offset + (obc1_state.address >> 2) + 0x200];
50         break;
51
52      default:
53         value = snes_ram[address];
54         break;
55   }
56
57   return value;
58}
59
60
61WRITE8_HANDLER( obc1_write )
62{
63   UINT16 address = offset & 0x1fff;
64   UINT8 temp;
65
66   switch(address)
67   {
68      case 0x1ff0:
69         snes_ram[obc1_state.offset + (obc1_state.address << 2) + 0] = data;
70         break;
71
72      case 0x1ff1:
73         snes_ram[obc1_state.offset + (obc1_state.address << 2) + 1] = data;
74         break;
75
76      case 0x1ff2:
77         snes_ram[obc1_state.offset + (obc1_state.address << 2) + 2] = data;
78         break;
79
80      case 0x1ff3:
81         snes_ram[obc1_state.offset + (obc1_state.address << 2) + 3] = data;
82         break;
83
84      case 0x1ff4:
85         temp = snes_ram[obc1_state.offset + (obc1_state.address >> 2) + 0x200];
86         temp = (temp & ~(3 << obc1_state.shift)) | ((data & 0x03) << obc1_state.shift);
87         snes_ram[obc1_state.offset + (obc1_state.address >> 2) + 0x200] = temp;
88         break;
89
90      case 0x1ff5:
91         obc1_state.offset = (data & 0x01) ? 0x1800 : 0x1c00;
92         snes_ram[address & 0x1fff] = data;
93         break;
94
95      case 0x1ff6:
96         obc1_state.address = data & 0x7f;
97         obc1_state.shift = (data & 0x03) << 1;
98         snes_ram[address & 0x1fff] = data;
99         break;
100
101      default:
102         snes_ram[address & 0x1fff] = data;
103         break;
104   }
105}
106
107void obc1_init( running_machine &machine )
108{
109   obc1_state.offset  = (snes_ram[0x1ff5] & 0x01) ? 0x1800 : 0x1c00;
110   obc1_state.address = (snes_ram[0x1ff6] & 0x7f);
111   obc1_state.shift   = (snes_ram[0x1ff6] & 0x03) << 1;
112
113   state_save_register_global(machine, obc1_state.offset);
114   state_save_register_global(machine, obc1_state.address);
115   state_save_register_global(machine, obc1_state.shift);
116}
trunk/src/mame/machine/snesrtc.c
r21589r21590
1/***************************************************************************
2
3  snesrtc.c
4
5  File to handle emulation of the SNES "S-RTC" add-on chip.
6
7  Based on C++ implementation by Byuu in BSNES.
8
9  Byuu's code is released under GNU General Public License
10  version 2 as published by the Free Software Foundation.
11  The implementation below is released under the MAME license
12  for use in MAME, MESS and derivatives by permission of the
13  author
14
15***************************************************************************/
16
17enum
18{
19   RTCM_Ready,
20   RTCM_Command,
21   RTCM_Read,
22   RTCM_Write
23};
24
25struct snes_rtc_state
26{
27   UINT8  ram[13];
28   INT32  mode;
29   INT8   index;
30};
31
32static snes_rtc_state rtc_state;
33
34static const UINT8 srtc_months[12] =
35{
36   31, 28, 31,
37   30, 31, 30,
38   31, 31, 30,
39   31, 30, 31
40};
41
42static void srtc_update_time( running_machine &machine )
43{
44   system_time curtime, *systime = &curtime;
45   machine.current_datetime(curtime);
46   rtc_state.ram[0] = systime->local_time.second % 10;
47   rtc_state.ram[1] = systime->local_time.second / 10;
48   rtc_state.ram[2] = systime->local_time.minute % 10;
49   rtc_state.ram[3] = systime->local_time.minute / 10;
50   rtc_state.ram[4] = systime->local_time.hour % 10;
51   rtc_state.ram[5] = systime->local_time.hour / 10;
52   rtc_state.ram[6] = systime->local_time.mday % 10;
53   rtc_state.ram[7] = systime->local_time.mday / 10;
54   rtc_state.ram[8] = systime->local_time.month;
55   rtc_state.ram[9] = (systime->local_time.year - 1000) % 10;
56   rtc_state.ram[10] = ((systime->local_time.year - 1000) / 10) % 10;
57   rtc_state.ram[11] = (systime->local_time.year - 1000) / 100;
58   rtc_state.ram[12] = systime->local_time.weekday % 7;
59}
60
61// Returns day-of-week for specified date
62// e.g. 0 = Sunday, 1 = Monday, ... 6 = Saturday
63// Usage: weekday(2008, 1, 1) returns the weekday of January 1st, 2008
64static UINT8 srtc_weekday( UINT32 year, UINT32 month, UINT32 day )
65{
66   UINT32 y = 1900, m = 1; // Epoch is 1900-01-01
67   UINT32 sum = 0;         // Number of days passed since epoch
68
69   year = MAX(1900, year);
70   month = MAX(1, MIN(12, month));
71   day = MAX(1, MIN(31, day));
72
73   while (y < year)
74   {
75      UINT8 leapyear = 0;
76      if ((y % 4) == 0)
77      {
78         leapyear = 1;
79         if ((y % 100) == 0 && (y % 400) != 0)
80         {
81            leapyear = 0;
82         }
83      }
84      sum += leapyear ? 366 : 365;
85      y++;
86   }
87
88   while (m < month)
89   {
90      UINT32 days = srtc_months[m - 1];
91      if (days == 28)
92      {
93         UINT8 leapyear = 0;
94         if ((y % 4) == 0)
95         {
96            leapyear = 1;
97            if ((y % 100) == 0 && (y % 400) != 0)
98            {
99               leapyear = 0;
100            }
101         }
102         days += leapyear ? 1 : 0;
103      }
104      sum += days;
105      m++;
106   }
107
108   sum += day - 1;
109   return (sum + 1) % 7; // 1900-01-01 was a Monday
110}
111
112UINT8 srtc_read( address_space &space, UINT16 addr )
113{
114   addr &= 0xffff;
115
116   if (addr == 0x2800)
117   {
118      if (rtc_state.mode != RTCM_Read)
119      {
120         return 0x00;
121      }
122
123      if (rtc_state.index < 0)
124      {
125         srtc_update_time(space.machine());
126         rtc_state.index++;
127         return 0x0f;
128      }
129      else if (rtc_state.index > 12)
130      {
131         rtc_state.index = -1;
132         return 0x0f;
133      }
134      else
135      {
136         return rtc_state.ram[rtc_state.index++];
137      }
138   }
139
140   return snes_open_bus_r(space, 0);
141}
142
143void srtc_write( running_machine &machine, UINT16 addr, UINT8 data )
144{
145   addr &= 0xffff;
146
147   if (addr == 0x2801)
148   {
149      data &= 0x0f;   // Only the low four bits are used
150
151      if (data == 0x0d)
152      {
153         rtc_state.mode = RTCM_Read;
154         rtc_state.index = -1;
155         return;
156      }
157
158      if (data == 0x0e)
159      {
160         rtc_state.mode = RTCM_Command;
161         return;
162      }
163
164      if (data == 0x0f)
165      {
166         return; // Unknown behaviour
167      }
168
169      if (rtc_state.mode == RTCM_Write)
170      {
171         if (rtc_state.index >= 0 && rtc_state.index < 12)
172         {
173            rtc_state.ram[rtc_state.index++] = data;
174
175            if (rtc_state.index == 12)
176            {
177               // Day of week is automatically calculated and written
178               UINT32 day   = rtc_state.ram[6] + rtc_state.ram[7] * 10;
179               UINT32 month = rtc_state.ram[8];
180               UINT32 year  = rtc_state.ram[9] + rtc_state.ram[10] * 10 + rtc_state.ram[11] * 100;
181               year += 1000;
182
183               rtc_state.ram[rtc_state.index++] = srtc_weekday(year, month, day);
184            }
185         }
186      }
187      else if (rtc_state.mode == RTCM_Command)
188      {
189         if (data == 0)
190         {
191            rtc_state.mode = RTCM_Write;
192            rtc_state.index = 0;
193         }
194         else if (data == 4)
195         {
196            UINT8 i;
197            rtc_state.mode = RTCM_Ready;
198            rtc_state.index = -1;
199            for(i = 0; i < 13; i++)
200            {
201               rtc_state.ram[i] = 0;
202            }
203         }
204         else
205         {
206            // Unknown behaviour
207            rtc_state.mode = RTCM_Ready;
208         }
209      }
210   }
211}
212
213void srtc_init( running_machine &machine )
214{
215   rtc_state.mode = RTCM_Read;
216   rtc_state.index = -1;
217   srtc_update_time(machine);
218
219   state_save_register_global_array(machine, rtc_state.ram);
220   state_save_register_global(machine, rtc_state.mode);
221   state_save_register_global(machine, rtc_state.index);
222}
trunk/src/mame/machine/cx4fn.c
r21589r21590
1/***************************************************************************
2
3    cx4fn.c
4
5    Code based on original work by zsKnight, anomie and Nach.
6    This implementation is based on C++ "cx4*.cpp" by byuu.
7    (up to date with source v 0.49).
8
9***************************************************************************/
10
11#include <math.h>
12#define CX4_Tan(a) (CX4_CosTable[a] ? ((((INT32)CX4_SinTable[a]) << 16) / CX4_CosTable[a]) : 0x80000000)
13#define CX4_sar(b, n) ((b) >> (n))
14#ifdef PI
15#undef PI
16#endif
17#define PI 3.1415926535897932384626433832795
18
19//Wireframe Helpers
20static void CX4_C4TransfWireFrame(void)
21{
22   cx4.c4x = (double)cx4.C4WFXVal;
23   cx4.c4y = (double)cx4.C4WFYVal;
24   cx4.c4z = (double)cx4.C4WFZVal - 0x95;
25
26   //Rotate X
27   cx4.tanval = -(double)cx4.C4WFX2Val * PI * 2 / 128;
28   cx4.c4y2   = cx4.c4y * cos(cx4.tanval) - cx4.c4z * sin(cx4.tanval);
29   cx4.c4z2   = cx4.c4y * sin(cx4.tanval) + cx4.c4z * cos(cx4.tanval);
30
31   //Rotate Y
32   cx4.tanval = -(double)cx4.C4WFY2Val * PI * 2 / 128;
33   cx4.c4x2   = cx4.c4x * cos(cx4.tanval)  + cx4.c4z2 * sin(cx4.tanval);
34   cx4.c4z    = cx4.c4x * -sin(cx4.tanval) + cx4.c4z2 * cos(cx4.tanval);
35
36   //Rotate Z
37   cx4.tanval = -(double)cx4.C4WFDist * PI * 2 / 128;
38   cx4.c4x    = cx4.c4x2 * cos(cx4.tanval) - cx4.c4y2 * sin(cx4.tanval);
39   cx4.c4y    = cx4.c4x2 * sin(cx4.tanval) + cx4.c4y2 * cos(cx4.tanval);
40
41   //Scale
42   cx4.C4WFXVal = (INT16)(cx4.c4x * cx4.C4WFScale / (0x90 * (cx4.c4z + 0x95)) * 0x95);
43   cx4.C4WFYVal = (INT16)(cx4.c4y * cx4.C4WFScale / (0x90 * (cx4.c4z + 0x95)) * 0x95);
44}
45
46static void CX4_C4CalcWireFrame(void)
47{
48   cx4.C4WFXVal = cx4.C4WFX2Val - cx4.C4WFXVal;
49   cx4.C4WFYVal = cx4.C4WFY2Val - cx4.C4WFYVal;
50
51   if(abs(cx4.C4WFXVal) > abs(cx4.C4WFYVal))
52   {
53      cx4.C4WFDist = abs(cx4.C4WFXVal) + 1;
54      cx4.C4WFYVal = (256 * (long)cx4.C4WFYVal) / abs(cx4.C4WFXVal);
55      cx4.C4WFXVal = (cx4.C4WFXVal < 0) ? -256 : 256;
56   }
57   else if(cx4.C4WFYVal != 0)
58   {
59      cx4.C4WFDist = abs(cx4.C4WFYVal) + 1;
60      cx4.C4WFXVal = (256 * (long)cx4.C4WFXVal) / abs(cx4.C4WFYVal);
61      cx4.C4WFYVal = (cx4.C4WFYVal < 0) ? -256 : 256;
62   }
63   else
64   {
65      cx4.C4WFDist = 0;
66   }
67}
68
69static void CX4_C4TransfWireFrame2(void)
70{
71   cx4.c4x = (double)cx4.C4WFXVal;
72   cx4.c4y = (double)cx4.C4WFYVal;
73   cx4.c4z = (double)cx4.C4WFZVal;
74
75   //Rotate X
76   cx4.tanval = -(double)cx4.C4WFX2Val * PI * 2 / 128;
77   cx4.c4y2   = cx4.c4y * cos(cx4.tanval) - cx4.c4z * sin(cx4.tanval);
78   cx4.c4z2   = cx4.c4y * sin(cx4.tanval) + cx4.c4z * cos(cx4.tanval);
79
80   //Rotate Y
81   cx4.tanval = -(double)cx4.C4WFY2Val * PI * 2 / 128;
82   cx4.c4x2   = cx4.c4x * cos(cx4.tanval)  + cx4.c4z2 * sin(cx4.tanval);
83   cx4.c4z    = cx4.c4x * -sin(cx4.tanval) + cx4.c4z2 * cos(cx4.tanval);
84
85   //Rotate Z
86   cx4.tanval = -(double)cx4.C4WFDist * PI * 2 / 128;
87   cx4.c4x    = cx4.c4x2 * cos(cx4.tanval) - cx4.c4y2 * sin(cx4.tanval);
88   cx4.c4y    = cx4.c4x2 * sin(cx4.tanval) + cx4.c4y2 * cos(cx4.tanval);
89
90   //Scale
91   cx4.C4WFXVal = (INT16)(cx4.c4x * cx4.C4WFScale / 0x100);
92   cx4.C4WFYVal = (INT16)(cx4.c4y * cx4.C4WFScale / 0x100);
93}
94
95static void CX4_C4DrawWireFrame(running_machine &machine)
96{
97   UINT32 line = CX4_readl(0x1f80);
98   UINT32 point1, point2;
99   INT16 X1, Y1, Z1;
100   INT16 X2, Y2, Z2;
101   UINT8 Color;
102   INT32 i;
103
104   address_space &space = machine.device<cpu_device>("maincpu")->space(AS_PROGRAM);
105   for(i = cx4.ram[0x0295]; i > 0; i--, line += 5)
106   {
107      if(space.read_byte(line) == 0xff &&
108         space.read_byte(line + 1) == 0xff)
109      {
110         INT32 tmp = line - 5;
111         while(space.read_byte(tmp + 2) == 0xff &&
112               space.read_byte(tmp + 3) == 0xff &&
113               (tmp + 2) >= 0)
114         {
115            tmp -= 5;
116         }
117         point1 = (CX4_read(0x1f82) << 16) |
118                  (space.read_byte(tmp + 2) << 8) |
119                  space.read_byte(tmp + 3);
120      }
121      else
122      {
123         point1 = (CX4_read(0x1f82) << 16) |
124                  (space.read_byte(line) << 8) |
125                  space.read_byte(line + 1);
126      }
127      point2 = (CX4_read(0x1f82) << 16) |
128               (space.read_byte(line + 2) << 8) |
129               space.read_byte(line + 3);
130
131      X1=(space.read_byte(point1 + 0) << 8) |
132         space.read_byte(point1 + 1);
133      Y1=(space.read_byte(point1 + 2) << 8) |
134         space.read_byte(point1 + 3);
135      Z1=(space.read_byte(point1 + 4) << 8) |
136         space.read_byte(point1 + 5);
137      X2=(space.read_byte(point2 + 0) << 8) |
138         space.read_byte(point2 + 1);
139      Y2=(space.read_byte(point2 + 2) << 8) |
140         space.read_byte(point2 + 3);
141      Z2=(space.read_byte(point2 + 4) << 8) |
142         space.read_byte(point2 + 5);
143      Color = space.read_byte(line + 4);
144      CX4_C4DrawLine(X1, Y1, Z1, X2, Y2, Z2, Color);
145   }
146}
147
148static void CX4_C4DrawLine(INT32 X1, INT32 Y1, INT16 Z1, INT32 X2, INT32 Y2, INT16 Z2, UINT8 Color)
149{
150   INT32 i;
151
152   //Transform coordinates
153   cx4.C4WFXVal  = (INT16)X1;
154   cx4.C4WFYVal  = (INT16)Y1;
155   cx4.C4WFZVal  = Z1;
156   cx4.C4WFScale = CX4_read(0x1f90);
157   cx4.C4WFX2Val = CX4_read(0x1f86);
158   cx4.C4WFY2Val = CX4_read(0x1f87);
159   cx4.C4WFDist  = CX4_read(0x1f88);
160   CX4_C4TransfWireFrame2();
161   X1 = (cx4.C4WFXVal + 48) << 8;
162   Y1 = (cx4.C4WFYVal + 48) << 8;
163
164   cx4.C4WFXVal = (INT16)X2;
165   cx4.C4WFYVal = (INT16)Y2;
166   cx4.C4WFZVal = Z2;
167   CX4_C4TransfWireFrame2();
168   X2 = (cx4.C4WFXVal + 48) << 8;
169   Y2 = (cx4.C4WFYVal + 48) << 8;
170
171   //Get line info
172   cx4.C4WFXVal  = (INT16)(X1 >> 8);
173   cx4.C4WFYVal  = (INT16)(Y1 >> 8);
174   cx4.C4WFX2Val = (INT16)(X2 >> 8);
175   cx4.C4WFY2Val = (INT16)(Y2 >> 8);
176   CX4_C4CalcWireFrame();
177   X2 = (INT16)cx4.C4WFXVal;
178   Y2 = (INT16)cx4.C4WFYVal;
179
180   //Render line
181   for(i = cx4.C4WFDist ? cx4.C4WFDist : 1; i > 0; i--)
182   {
183      if(X1 > 0xff && Y1 > 0xff && X1 < 0x6000 && Y1 < 0x6000)
184      {
185         UINT16 addr = (((Y1 >> 8) >> 3) << 8) - (((Y1 >> 8) >> 3) << 6) + (((X1 >> 8) >> 3) << 4) + ((Y1 >> 8) & 7) * 2;
186         UINT8 bit = 0x80 >> ((X1 >> 8) & 7);
187         cx4.ram[addr + 0x300] &= ~bit;
188         cx4.ram[addr + 0x301] &= ~bit;
189         if(Color & 1)
190         {
191            cx4.ram[addr + 0x300] |= bit;
192         }
193         if(Color & 2)
194         {
195            cx4.ram[addr + 0x301] |= bit;
196         }
197      }
198      X1 += X2;
199      Y1 += Y2;
200   }
201}
202
203static void CX4_C4DoScaleRotate(int row_padding)
204{
205   INT16 A, B, C, D;
206   INT32 x, y;
207
208   //Calculate Pixel Resolution
209   UINT8 w = CX4_read(0x1f89) & ~7;
210   UINT8 h = CX4_read(0x1f8c) & ~7;
211
212   INT32 Cx = (INT16)CX4_readw(0x1f83);
213   INT32 Cy = (INT16)CX4_readw(0x1f86);
214
215   INT32 LineX, LineY;
216   UINT32 X, Y;
217   UINT8 byte;
218   INT32 outidx = 0;
219   UINT8 bit    = 0x80;
220
221   //Calculate matrix
222   INT32 XScale = CX4_readw(0x1f8f);
223   INT32 YScale = CX4_readw(0x1f92);
224
225   if(XScale & 0x8000)
226   {
227      XScale = 0x7fff;
228   }
229   if(YScale & 0x8000)
230   {
231      YScale = 0x7fff;
232   }
233
234   if(CX4_readw(0x1f80) == 0)
235   { //no rotation
236      A = (INT16)XScale;
237      B = 0;
238      C = 0;
239      D = (INT16)YScale;
240   }
241   else if(CX4_readw(0x1f80) == 128)
242   { //90 degree rotation
243      A = 0;
244      B = (INT16)(-YScale);
245      C = (INT16)XScale;
246      D = 0;
247   }
248   else if(CX4_readw(0x1f80) == 256)
249   { //180 degree rotation
250      A = (INT16)(-XScale);
251      B = 0;
252      C = 0;
253      D = (INT16)(-YScale);
254   }
255   else if(CX4_readw(0x1f80) == 384)
256   { //270 degree rotation
257      A = 0;
258      B = (INT16)YScale;
259      C = (INT16)(-XScale);
260      D = 0;
261   }
262   else
263   {
264      A = (INT16)  CX4_sar(CX4_CosTable[CX4_readw(0x1f80) & 0x1ff] * XScale, 15);
265      B = (INT16)(-CX4_sar(CX4_SinTable[CX4_readw(0x1f80) & 0x1ff] * YScale, 15));
266      C = (INT16)  CX4_sar(CX4_SinTable[CX4_readw(0x1f80) & 0x1ff] * XScale, 15);
267      D = (INT16)  CX4_sar(CX4_CosTable[CX4_readw(0x1f80) & 0x1ff] * YScale, 15);
268   }
269
270   //Clear the output RAM
271   memset(cx4.ram, 0, (w + row_padding / 4) * h / 2);
272
273   //Calculate start position (i.e. (Ox, Oy) = (0, 0))
274   //The low 12 bits are fractional, so (Cx<<12) gives us the Cx we want in
275   //the function. We do Cx*A etc normally because the matrix parameters
276   //already have the fractional parts.
277   LineX = (Cx << 12) - Cx * A - Cx * B;
278   LineY = (Cy << 12) - Cy * C - Cy * D;
279
280   //Start loop
281   for(y = 0; y < h; y++)
282   {
283      X = LineX;
284      Y = LineY;
285      for(x = 0; x < w; x++)
286      {
287         if((X >> 12) >= w || (Y >> 12) >= h)
288         {
289            byte = 0;
290         }
291         else
292         {
293            UINT32 addr = (Y >> 12) * w + (X >> 12);
294            byte = CX4_read(0x600 + (addr >> 1));
295            if(addr & 1)
296            {
297               byte >>= 4;
298            }
299         }
300
301         //De-bitplanify
302         if(byte & 1) { cx4.ram[outidx     ] |= bit; }
303         if(byte & 2) { cx4.ram[outidx +  1] |= bit; }
304         if(byte & 4) { cx4.ram[outidx + 16] |= bit; }
305         if(byte & 8) { cx4.ram[outidx + 17] |= bit; }
306
307         bit >>= 1;
308         if(!bit)
309         {
310            bit     = 0x80;
311            outidx += 32;
312         }
313
314         X += A; //Add 1 to output x => add an A and a C
315         Y += C;
316      }
317      outidx += 2 + row_padding;
318      if(outidx & 0x10)
319      {
320         outidx &= ~0x10;
321      }
322      else
323      {
324         outidx -= w * 4 + row_padding;
325      }
326      LineX += B; //Add 1 to output y => add a B and a D
327      LineY += D;
328   }
329}
trunk/src/mame/machine/snescx4.c
r21589r21590
1/***************************************************************************
2
3    snescx4.c
4
5    File to handle emulation of the SNES "CX4" add-on chip.
6
7    Code based on original work by zsKnight, anomie and Nach.
8    This implementation is based on C++ "cx4*.cpp" by byuu
9    (up to date with source v 0.49).
10
11***************************************************************************/
12
13#include "emu.h"
14#include "snescx4.h"
15
16static CX4 cx4;
17
18static UINT16 CX4_readw(UINT16 addr);
19static UINT32 CX4_readl(UINT16 addr);
20
21static void CX4_writew(running_machine &machine, UINT16 addr, UINT16 data);
22//static void CX4_writel(running_machine &machine, UINT16 addr, UINT32 data);
23
24static void CX4_C4DrawLine(INT32 X1, INT32 Y1, INT16 Z1, INT32 X2, INT32 Y2, INT16 Z2, UINT8 Color);
25
26#include "cx4data.c"
27#include "cx4fn.c"
28
29static UINT32 CX4_ldr(UINT8 r)
30{
31   UINT16 addr = 0x0080 + (r * 3);
32   return (cx4.reg[addr + 0] <<  0)
33         | (cx4.reg[addr + 1] <<  8)
34         | (cx4.reg[addr + 2] << 16);
35}
36
37static void CX4_str(UINT8 r, UINT32 data)
38{
39   UINT16 addr = 0x0080 + (r * 3);
40   cx4.reg[addr + 0] = (data >>  0);
41   cx4.reg[addr + 1] = (data >>  8);
42   cx4.reg[addr + 2] = (data >> 16);
43}
44
45static void CX4_mul(UINT32 x, UINT32 y, UINT32 *rl, UINT32 *rh)
46{
47   INT64 rx = x & 0xffffff;
48   INT64 ry = y & 0xffffff;
49   if(rx & 0x800000)rx |= ~0x7fffff;
50   if(ry & 0x800000)ry |= ~0x7fffff;
51
52   rx *= ry;
53
54   *rl = (rx)       & 0xffffff;
55   *rh = (rx >> 24) & 0xffffff;
56}
57
58static UINT32 CX4_sin(UINT32 rx)
59{
60   cx4.r0 = rx & 0x1ff;
61   if(cx4.r0 & 0x100)
62   {
63      cx4.r0 ^= 0x1ff;
64   }
65   if(cx4.r0 & 0x080)
66   {
67      cx4.r0 ^= 0x0ff;
68   }
69   if(rx & 0x100)
70   {
71      return CX4_sin_table[cx4.r0 + 0x80];
72   }
73   else
74   {
75      return CX4_sin_table[cx4.r0];
76   }
77}
78
79static UINT32 CX4_cos(UINT32 rx)
80{
81   return CX4_sin(rx + 0x080);
82}
83
84static void CX4_immediate_reg(UINT32 start)
85{
86   UINT32 i = 0;
87   cx4.r0 = CX4_ldr(0);
88   for(i = start; i < 48; i++)
89   {
90      if((cx4.r0 & 0x0fff) < 0x0c00)
91      {
92         cx4.ram[cx4.r0 & 0x0fff] = CX4_immediate_data[i];
93      }
94      cx4.r0++;
95   }
96   CX4_str(0, cx4.r0);
97}
98
99static void CX4_transfer_data(running_machine &machine)
100{
101   UINT32 src;
102   UINT16 dest, count;
103   UINT32 i;
104
105   src   = (cx4.reg[0x40]) | (cx4.reg[0x41] << 8) | (cx4.reg[0x42] << 16);
106   count = (cx4.reg[0x43]) | (cx4.reg[0x44] << 8);
107   dest  = (cx4.reg[0x45]) | (cx4.reg[0x46] << 8);
108
109   address_space &space = machine.device<cpu_device>("maincpu")->space(AS_PROGRAM);
110   for(i=0;i<count;i++)
111   {
112      CX4_write(machine, dest++, space.read_byte(src++));
113   }
114}
115
116#include "cx4oam.c"
117#include "cx4ops.c"
118
119void CX4_write(running_machine &machine, UINT32 addr, UINT8 data)
120{
121   addr &= 0x1fff;
122
123   if(addr < 0x0c00)
124   {
125      //ram
126      cx4.ram[addr] = data;
127      return;
128   }
129
130   if(addr < 0x1f00)
131   {
132      //unmapped
133      return;
134   }
135
136   //command register
137   cx4.reg[addr & 0xff] = data;
138
139   if(addr == 0x1f47)
140   {
141      //memory transfer
142      CX4_transfer_data(machine);
143      return;
144   }
145
146   if(addr == 0x1f4f)
147   {
148      //c4 command
149      if(cx4.reg[0x4d] == 0x0e && !(data & 0xc3))
150      {
151         //c4 test command
152         cx4.reg[0x80] = data >> 2;
153         return;
154      }
155
156      switch(data)
157      {
158         case 0x00: CX4_op00(machine); break;
159         case 0x01: CX4_op01(machine); break;
160         case 0x05: CX4_op05(machine); break;
161         case 0x0d: CX4_op0d(machine); break;
162         case 0x10: CX4_op10(); break;
163         case 0x13: CX4_op13(); break;
164         case 0x15: CX4_op15(machine); break;
165         case 0x1f: CX4_op1f(machine); break;
166         case 0x22: CX4_op22(); break;
167         case 0x25: CX4_op25(); break;
168         case 0x2d: CX4_op2d(machine); break;
169         case 0x40: CX4_op40(); break;
170         case 0x54: CX4_op54(); break;
171         case 0x5c: CX4_op5c(); break;
172         case 0x5e: CX4_op5e(); break;
173         case 0x60: CX4_op60(); break;
174         case 0x62: CX4_op62(); break;
175         case 0x64: CX4_op64(); break;
176         case 0x66: CX4_op66(); break;
177         case 0x68: CX4_op68(); break;
178         case 0x6a: CX4_op6a(); break;
179         case 0x6c: CX4_op6c(); break;
180         case 0x6e: CX4_op6e(); break;
181         case 0x70: CX4_op70(); break;
182         case 0x72: CX4_op72(); break;
183         case 0x74: CX4_op74(); break;
184         case 0x76: CX4_op76(); break;
185         case 0x78: CX4_op78(); break;
186         case 0x7a: CX4_op7a(); break;
187         case 0x7c: CX4_op7c(); break;
188         case 0x89: CX4_op89(); break;
189      }
190   }
191}
192
193#ifdef UNUSED_FUNCTION
194void CX4_writeb(running_machine &machine, UINT16 addr, UINT8 data)
195{
196   CX4_write(machine, addr,     data);
197}
198#endif
199
200static void CX4_writew(running_machine &machine, UINT16 addr, UINT16 data)
201{
202   CX4_write(machine, addr + 0, data >> 0);
203   CX4_write(machine, addr + 1, data >> 8);
204}
205
206#ifdef UNUSED_FUNCTION
207void CX4_writel(running_machine &machine, UINT16 addr, UINT32 data)
208{
209   CX4_write(machine, addr + 0, data >>  0);
210   CX4_write(machine, addr + 1, data >>  8);
211   CX4_write(machine, addr + 2, data >> 16);
212}
213#endif
214
215UINT8 CX4_read(UINT32 addr)
216{
217   addr &= 0x1fff;
218
219   if(addr < 0x0c00)
220   {
221      return cx4.ram[addr];
222   }
223
224   if(addr >= 0x1f00)
225   {
226      return cx4.reg[addr & 0xff];
227   }
228
229   return 0xff;
230}
231
232#ifdef UNUSED_FUNCTION
233UINT8 CX4_readb(UINT16 addr)
234{
235   return CX4_read(addr);
236}
237#endif
238
239static UINT16 CX4_readw(UINT16 addr)
240{
241   return CX4_read(addr) | (CX4_read(addr + 1) << 8);
242}
243
244static UINT32 CX4_readl(UINT16 addr)
245{
246   return CX4_read(addr) | (CX4_read(addr + 1) << 8) | (CX4_read(addr + 2) << 16);
247}
248
249#ifdef UNUSED_FUNCTION
250void CX4_reset()
251{
252   memset(cx4.ram, 0, 0x0c00);
253   memset(cx4.reg, 0, 0x0100);
254}
255#endif
trunk/src/mame/machine/snescx4.h
r21589r21590
1/***************************************************************************
2
3    snescx4.h
4
5    Code based on original work by zsKnight, anomie and Nach.
6    This implementation is based on C++ "cx4*.cpp" by byuu
7    (up to date with source v 0.49).
8
9***************************************************************************/
10
11struct CX4
12{
13      UINT8 ram[0x0c00];
14      UINT8 reg[0x0100];
15      UINT32 r0, r1, r2,  r3,  r4,  r5,  r6,  r7,
16               r8, r9, r10, r11, r12, r13, r14, r15;
17
18      INT16 C4WFXVal, C4WFYVal, C4WFZVal, C4WFX2Val, C4WFY2Val, C4WFDist, C4WFScale;
19      INT16 C41FXVal, C41FYVal, C41FAngleRes, C41FDist, C41FDistVal;
20
21      double tanval;
22      double c4x, c4y, c4z;
23      double c4x2, c4y2, c4z2;
24};
trunk/src/mame/machine/snes7110.c
r21589r21590
1/***************************************************************************
2
3  snes7110.c
4
5  File to handle emulation of the SNES "SPC7110" add-on chip.
6
7  Based on C++ implementation by Byuu in BSNES.
8
9  Byuu's code is released under GNU General Public License
10  version 2 as published by the Free Software Foundation.
11  The implementation below is released under the MAME license
12  for use in MAME, MESS and derivatives by permission of the
13  author
14
15***************************************************************************/
16
17
18#define SPC7110_DECOMP_BUFFER_SIZE 64
19
20static const UINT8 spc7110_evolution_table[53][4] =
21{
22   { 0x5a,  1,  1, 1 },
23   { 0x25,  6,  2, 0 },
24   { 0x11,  8,  3, 0 },
25   { 0x08, 10,  4, 0 },
26   { 0x03, 12,  5, 0 },
27   { 0x01, 15,  5, 0 },
28
29   { 0x5a,  7,  7, 1 },
30   { 0x3f, 19,  8, 0 },
31   { 0x2c, 21,  9, 0 },
32   { 0x20, 22, 10, 0 },
33   { 0x17, 23, 11, 0 },
34   { 0x11, 25, 12, 0 },
35   { 0x0c, 26, 13, 0 },
36   { 0x09, 28, 14, 0 },
37   { 0x07, 29, 15, 0 },
38   { 0x05, 31, 16, 0 },
39   { 0x04, 32, 17, 0 },
40   { 0x03, 34, 18, 0 },
41   { 0x02, 35,  5, 0 },
42
43   { 0x5a, 20, 20, 1 },
44   { 0x48, 39, 21, 0 },
45   { 0x3a, 40, 22, 0 },
46   { 0x2e, 42, 23, 0 },
47   { 0x26, 44, 24, 0 },
48   { 0x1f, 45, 25, 0 },
49   { 0x19, 46, 26, 0 },
50   { 0x15, 25, 27, 0 },
51   { 0x11, 26, 28, 0 },
52   { 0x0e, 26, 29, 0 },
53   { 0x0b, 27, 30, 0 },
54   { 0x09, 28, 31, 0 },
55   { 0x08, 29, 32, 0 },
56   { 0x07, 30, 33, 0 },
57   { 0x05, 31, 34, 0 },
58   { 0x04, 33, 35, 0 },
59   { 0x04, 33, 36, 0 },
60   { 0x03, 34, 37, 0 },
61   { 0x02, 35, 38, 0 },
62   { 0x02, 36,  5, 0 },
63
64   { 0x58, 39, 40, 1 },
65   { 0x4d, 47, 41, 0 },
66   { 0x43, 48, 42, 0 },
67   { 0x3b, 49, 43, 0 },
68   { 0x34, 50, 44, 0 },
69   { 0x2e, 51, 45, 0 },
70   { 0x29, 44, 46, 0 },
71   { 0x25, 45, 24, 0 },
72
73   { 0x56, 47, 48, 1 },
74   { 0x4f, 47, 49, 0 },
75   { 0x47, 48, 50, 0 },
76   { 0x41, 49, 51, 0 },
77   { 0x3c, 50, 52, 0 },
78   { 0x37, 51, 43, 0 },
79};
80
81static const UINT8 spc7110_mode2_context_table[32][2] =
82{
83   {  1,  2 },
84
85   {  3,  8 },
86   { 13, 14 },
87
88   { 15, 16 },
89   { 17, 18 },
90   { 19, 20 },
91   { 21, 22 },
92   { 23, 24 },
93   { 25, 26 },
94   { 25, 26 },
95   { 25, 26 },
96   { 25, 26 },
97   { 25, 26 },
98   { 27, 28 },
99   { 29, 30 },
100
101   { 31, 31 },
102   { 31, 31 },
103   { 31, 31 },
104   { 31, 31 },
105   { 31, 31 },
106   { 31, 31 },
107   { 31, 31 },
108   { 31, 31 },
109   { 31, 31 },
110   { 31, 31 },
111   { 31, 31 },
112   { 31, 31 },
113   { 31, 31 },
114   { 31, 31 },
115   { 31, 31 },
116   { 31, 31 },
117
118   { 31, 31 },
119};
120
121class SPC7110Decomp
122{
123public:
124   SPC7110Decomp(running_machine &machine, UINT32 size);
125
126   running_machine &machine() const { return m_machine; }
127
128   void init(running_machine &machine, UINT8 *ROM, UINT32 mode, UINT32 offset, UINT32 index);
129   void reset();
130
131   UINT8 read(UINT8 *ROM);
132   void write(UINT8 data);
133   void mode0(UINT8 init, UINT8 *ROM);
134   void mode1(UINT8 init, UINT8 *ROM);
135   void mode2(UINT8 init, UINT8 *ROM);
136
137   UINT8 dataread(UINT8 *ROM);
138   UINT8 probability(UINT32 n);
139   UINT8 next_lps(UINT32 n);
140   UINT8 next_mps(UINT32 n);
141   UINT8 toggle_invert(UINT32 n);
142   UINT32 morton_2x8(UINT32 data);
143   UINT32 morton_4x8(UINT32 data);
144
145   UINT32 m_decomp_mode;
146   UINT32 m_decomp_offset;
147
148   UINT8 *m_decomp_buffer;
149   UINT32 m_decomp_buffer_rdoffset;
150   UINT32 m_decomp_buffer_wroffset;
151   UINT32 m_decomp_buffer_length;
152
153   struct ContextState
154   {
155      UINT8 index;
156      UINT8 invert;
157   } m_context[32];
158
159   UINT32 m_morton16[2][256];
160   UINT32 m_morton32[4][256];
161
162
163private:
164   running_machine& m_machine;
165   UINT32 m_rom_size;
166};
167
168SPC7110Decomp::SPC7110Decomp(running_machine &machine, UINT32 size)
169      :  m_machine(machine),
170      m_rom_size(size)
171{
172   m_decomp_buffer = (UINT8*)auto_alloc_array(machine, UINT8, SPC7110_DECOMP_BUFFER_SIZE);
173   reset();
174
175   for (int i = 0; i < 256; i++)
176   {
177      #define map(x, y) (((i >> x) & 1) << y)
178      //2x8-bit
179      m_morton16[1][i] = map(7, 15) + map(6,  7) + map(5, 14) + map(4,  6)
180                     + map(3, 13) + map(2,  5) + map(1, 12) + map(0,  4);
181      m_morton16[0][i] = map(7, 11) + map(6,  3) + map(5, 10) + map(4,  2)
182                     + map(3,  9) + map(2,  1) + map(1,  8) + map(0,  0);
183      //4x8-bit
184      m_morton32[3][i] = map(7, 31) + map(6, 23) + map(5, 15) + map(4,  7)
185                     + map(3, 30) + map(2, 22) + map(1, 14) + map(0,  6);
186      m_morton32[2][i] = map(7, 29) + map(6, 21) + map(5, 13) + map(4,  5)
187                     + map(3, 28) + map(2, 20) + map(1, 12) + map(0,  4);
188      m_morton32[1][i] = map(7, 27) + map(6, 19) + map(5, 11) + map(4,  3)
189                     + map(3, 26) + map(2, 18) + map(1, 10) + map(0,  2);
190      m_morton32[0][i] = map(7, 25) + map(6, 17) + map(5,  9) + map(4,  1)
191                     + map(3, 24) + map(2, 16) + map(1,  8) + map(0,  0);
192      #undef map
193   }
194}
195
196void SPC7110Decomp::reset()
197{
198   //mode 3 is invalid; this is treated as a special case to always return 0x00
199   //set to mode 3 so that reading decomp port before starting first decomp will return 0x00
200   m_decomp_mode = 3;
201
202   m_decomp_buffer_rdoffset = 0;
203   m_decomp_buffer_wroffset = 0;
204   m_decomp_buffer_length   = 0;
205}
206
207void SPC7110Decomp::init(running_machine &machine, UINT8 *ROM, UINT32 mode, UINT32 offset, UINT32 index)
208{
209   m_decomp_mode = mode;
210   m_decomp_offset = offset;
211
212   m_decomp_buffer_rdoffset = 0;
213   m_decomp_buffer_wroffset = 0;
214   m_decomp_buffer_length   = 0;
215
216   //reset context states
217   for (int i = 0; i < 32; i++)
218   {
219      m_context[i].index  = 0;
220      m_context[i].invert = 0;
221   }
222
223   switch (m_decomp_mode)
224   {
225      case 0: mode0(1, ROM); break;
226      case 1: mode1(1, ROM); break;
227      case 2: mode2(1, ROM); break;
228   }
229
230   //decompress up to requested output data index
231   while (index--)
232   {
233      read(ROM);
234   }
235}
236
237UINT8 SPC7110Decomp::read(UINT8 *ROM)
238{
239   UINT8 data;
240
241   if (m_decomp_buffer_length == 0)
242   {
243      //decompress at least (SPC7110_DECOMP_BUFFER_SIZE / 2) bytes to the buffer
244      switch (m_decomp_mode)
245      {
246         case 0:
247            mode0(0, ROM);
248            break;
249
250         case 1:
251            mode1(0, ROM);
252            break;
253
254         case 2:
255            mode2(0, ROM);
256            break;
257
258         default:
259            return 0x00;
260      }
261   }
262
263   data = m_decomp_buffer[m_decomp_buffer_rdoffset++];
264   m_decomp_buffer_rdoffset &= SPC7110_DECOMP_BUFFER_SIZE - 1;
265   m_decomp_buffer_length--;
266   return data;
267}
268
269void SPC7110Decomp::write(UINT8 data)
270{
271   m_decomp_buffer[m_decomp_buffer_wroffset++] = data;
272   m_decomp_buffer_wroffset &= SPC7110_DECOMP_BUFFER_SIZE - 1;
273   m_decomp_buffer_length++;
274}
275
276UINT8 SPC7110Decomp::dataread(UINT8 *ROM)
277{
278   UINT32 size = m_rom_size - 0x100000;
279   while (m_decomp_offset >= size)
280   {
281      m_decomp_offset -= size;
282   }
283   return ROM[0x100000 + m_decomp_offset++];
284}
285
286void SPC7110Decomp::mode0(UINT8 init, UINT8 *ROM)
287{
288   static UINT8 val, in, span;
289   static INT32 out, inverts, lps, in_count;
290
291   if (init == 1)
292   {
293      out = inverts = lps = 0;
294      span = 0xff;
295      val = dataread(ROM);
296      in = dataread(ROM);
297      in_count = 8;
298      return;
299   }
300
301   while (m_decomp_buffer_length < (SPC7110_DECOMP_BUFFER_SIZE >> 1))
302   {
303      for (int bit = 0; bit < 8; bit++)
304      {
305         //get context
306         UINT8 mask = (1 << (bit & 3)) - 1;
307         UINT8 con = mask + ((inverts & mask) ^ (lps & mask));
308         UINT32 prob, mps, flag_lps;
309         UINT32 shift = 0;
310         if (bit > 3)
311         {
312            con += 15;
313         }
314
315         //get prob and mps
316         prob = probability(con);
317         mps = (((out >> 15) & 1) ^ m_context[con].invert);
318
319         //get bit
320         if (val <= span - prob) //mps
321         {
322            span = span - prob;
323            out = (out << 1) + mps;
324            flag_lps = 0;
325         }
326         else //lps
327         {
328            val = val - (span - (prob - 1));
329            span = prob - 1;
330            out = (out << 1) + 1 - mps;
331            flag_lps = 1;
332         }
333
334         //renormalize
335         while (span < 0x7f)
336         {
337            shift++;
338
339            span = (span << 1) + 1;
340            val = (val << 1) + (in >> 7);
341
342            in <<= 1;
343            if (--in_count == 0)
344            {
345               in = dataread(ROM);
346               in_count = 8;
347            }
348         }
349
350         //update processing info
351         lps = (lps << 1) + flag_lps;
352         inverts = (inverts << 1) + m_context[con].invert;
353
354         //update context state
355         if (flag_lps & toggle_invert(con))
356         {
357            m_context[con].invert ^= 1;
358         }
359         if (flag_lps)
360         {
361            m_context[con].index = next_lps(con);
362         }
363         else if (shift)
364         {
365            m_context[con].index = next_mps(con);
366         }
367      }
368
369      //save byte
370      write(out);
371   }
372}
373
374void SPC7110Decomp::mode1(UINT8 init, UINT8 *ROM)
375{
376   static INT32 pixelorder[4], realorder[4];
377   static UINT8 in, val, span;
378   static INT32 out, inverts, lps, in_count;
379
380   if (init == 1)
381   {
382      for (int i = 0; i < 4; i++)
383      {
384         pixelorder[i] = i;
385      }
386      out = inverts = lps = 0;
387      span = 0xff;
388      val = dataread(ROM);
389      in = dataread(ROM);
390      in_count = 8;
391      return;
392   }
393
394   while (m_decomp_buffer_length < (SPC7110_DECOMP_BUFFER_SIZE >> 1))
395   {
396      UINT16 data;
397      for (int pixel = 0; pixel < 8; pixel++)
398      {
399         //get first symbol context
400         UINT32 a = ((out >> (1 * 2)) & 3);
401         UINT32 b = ((out >> (7 * 2)) & 3);
402         UINT32 c = ((out >> (8 * 2)) & 3);
403         UINT32 con = (a == b) ? (b != c) : (b == c) ? 2 : 4 - (a == c);
404
405         //update pixel order
406         UINT32 m, n;
407         for (m = 0; m < 4; m++)
408         {
409            if (pixelorder[m] == a)
410            {
411               break;
412            }
413         }
414         for (n = m; n > 0; n--)
415         {
416            pixelorder[n] = pixelorder[n - 1];
417         }
418         pixelorder[0] = a;
419
420         //calculate the real pixel order
421         for (m = 0; m < 4; m++)
422         {
423            realorder[m] = pixelorder[m];
424         }
425
426         //rotate reference pixel c value to top
427         for (m = 0; m < 4; m++)
428         {
429            if (realorder[m] == c)
430            {
431               break;
432            }
433         }
434         for (n = m; n > 0; n--)
435         {
436            realorder[n] = realorder[n - 1];
437         }
438         realorder[0] = c;
439
440         //rotate reference pixel b value to top
441         for (m = 0; m < 4; m++)
442         {
443            if (realorder[m] == b)
444            {
445               break;
446            }
447         }
448         for (n = m; n > 0; n--)
449         {
450            realorder[n] = realorder[n - 1];
451         }
452         realorder[0] = b;
453
454         //rotate reference pixel a value to top
455         for (m = 0; m < 4; m++)
456         {
457            if (realorder[m] == a)
458            {
459               break;
460            }
461         }
462         for (n = m; n > 0; n--)
463         {
464            realorder[n] = realorder[n - 1];
465         }
466         realorder[0] = a;
467
468         //get 2 symbols
469         for (int bit = 0; bit < 2; bit++)
470         {
471            //get prob
472            UINT32 prob = probability(con);
473            UINT32 shift = 0;
474
475            //get symbol
476            UINT32 flag_lps;
477            if (val <= span - prob) //mps
478            {
479               span = span - prob;
480               flag_lps = 0;
481            }
482            else //lps
483            {
484               val = val - (span - (prob - 1));
485               span = prob - 1;
486               flag_lps = 1;
487            }
488
489            //renormalize
490            while (span < 0x7f)
491            {
492               shift++;
493
494               span = (span << 1) + 1;
495               val = (val << 1) + (in >> 7);
496
497               in <<= 1;
498               if (--in_count == 0)
499               {
500                  in = dataread(ROM);
501                  in_count = 8;
502               }
503            }
504
505            //update processing info
506            lps = (lps << 1) + flag_lps;
507            inverts = (inverts << 1) + m_context[con].invert;
508
509            //update context state
510            if (flag_lps & toggle_invert(con))
511            {
512               m_context[con].invert ^= 1;
513            }
514            if (flag_lps)
515            {
516               m_context[con].index = next_lps(con);
517            }
518            else if (shift)
519            {
520               m_context[con].index = next_mps(con);
521            }
522
523            //get next context
524            con = 5 + (con << 1) + ((lps ^ inverts) & 1);
525         }
526
527         //get pixel
528         b = realorder[(lps ^ inverts) & 3];
529         out = (out << 2) + b;
530      }
531
532      //turn pixel data into bitplanes
533      data = morton_2x8(out);
534      write(data >> 8);
535      write(data >> 0);
536   }
537}
538
539void SPC7110Decomp::mode2(UINT8 init, UINT8 *ROM)
540{
541   static INT32 pixelorder[16], realorder[16];
542   static UINT8 bitplanebuffer[16], buffer_index;
543   static UINT8 in, val, span;
544   static INT32 out0, out1, inverts, lps, in_count;
545
546   if (init == 1)
547   {
548      for (int i = 0; i < 16; i++)
549      {
550         pixelorder[i] = i;
551      }
552      buffer_index = 0;
553      out0 = out1 = inverts = lps = 0;
554      span = 0xff;
555      val = dataread(ROM);
556      in = dataread(ROM);
557      in_count = 8;
558      return;
559   }
560
561   while (m_decomp_buffer_length < (SPC7110_DECOMP_BUFFER_SIZE >> 1))
562   {
563      UINT32 data;
564      for (int pixel = 0; pixel < 8; pixel++)
565      {
566         //get first symbol context
567         UINT32 a = ((out0 >> (0 * 4)) & 15);
568         UINT32 b = ((out0 >> (7 * 4)) & 15);
569         UINT32 c = ((out1 >> (0 * 4)) & 15);
570         UINT32 con = 0;
571         UINT32 refcon = (a == b) ? (b != c) : (b == c) ? 2 : 4 - (a == c);
572
573         //update pixel order
574         UINT32 m, n;
575         for (m = 0; m < 16; m++)
576         {
577            if (pixelorder[m] == a)
578            {
579               break;
580            }
581         }
582         for (n = m; n >  0; n--)
583         {
584            pixelorder[n] = pixelorder[n - 1];
585         }
586         pixelorder[0] = a;
587
588         //calculate the real pixel order
589         for (m = 0; m < 16; m++)
590         {
591            realorder[m] = pixelorder[m];
592         }
593
594         //rotate reference pixel c value to top
595         for (m = 0; m < 16; m++)
596         {
597            if (realorder[m] == c)
598            {
599               break;
600            }
601         }
602         for (n = m; n >  0; n--)
603         {
604            realorder[n] = realorder[n - 1];
605         }
606         realorder[0] = c;
607
608         //rotate reference pixel b value to top
609         for (m = 0; m < 16; m++)
610         {
611            if (realorder[m] == b)
612            {
613               break;
614            }
615         }
616         for (n = m; n >  0; n--)
617         {
618            realorder[n] = realorder[n - 1];
619         }
620         realorder[0] = b;
621
622         //rotate reference pixel a value to top
623         for (m = 0; m < 16; m++)
624         {
625            if (realorder[m] == a)
626            {
627               break;
628            }
629         }
630         for (n = m; n >  0; n--)
631         {
632            realorder[n] = realorder[n - 1];
633         }
634         realorder[0] = a;
635
636         //get 4 symbols
637         for (int bit = 0; bit < 4; bit++)
638         {
639            UINT32 invertbit, shift;
640
641            //get prob
642            UINT32 prob = probability(con);
643
644            //get symbol
645            UINT32 flag_lps;
646            if (val <= span - prob) //mps
647            {
648               span = span - prob;
649               flag_lps = 0;
650            }
651            else //lps
652            {
653               val = val - (span - (prob - 1));
654               span = prob - 1;
655               flag_lps = 1;
656            }
657
658            //renormalize
659            shift = 0;
660            while (span < 0x7f)
661            {
662               shift++;
663
664               span = (span << 1) + 1;
665               val = (val << 1) + (in >> 7);
666
667               in <<= 1;
668               if (--in_count == 0)
669               {
670                  in = dataread(ROM);
671                  in_count = 8;
672               }
673            }
674
675            //update processing info
676            lps = (lps << 1) + flag_lps;
677            invertbit = m_context[con].invert;
678            inverts = (inverts << 1) + invertbit;
679
680            //update context state
681            if (flag_lps & toggle_invert(con))
682            {
683               m_context[con].invert ^= 1;
684            }
685            if (flag_lps)
686            {
687               m_context[con].index = next_lps(con);
688            }
689            else if (shift)
690            {
691               m_context[con].index = next_mps(con);
692            }
693
694            //get next context
695            con = spc7110_mode2_context_table[con][flag_lps ^ invertbit] + (con == 1 ? refcon : 0);
696         }
697
698         //get pixel
699         b = realorder[(lps ^ inverts) & 0x0f];
700         out1 = (out1 << 4) + ((out0 >> 28) & 0x0f);
701         out0 = (out0 << 4) + b;
702      }
703
704      //convert pixel data into bitplanes
705      data = morton_4x8(out0);
706      write(data >> 24);
707      write(data >> 16);
708      bitplanebuffer[buffer_index++] = data >> 8;
709      bitplanebuffer[buffer_index++] = data >> 0;
710
711      if (buffer_index == 16)
712      {
713         for (int i = 0; i < 16; i++)
714         {
715            write(bitplanebuffer[i]);
716         }
717         buffer_index = 0;
718      }
719   }
720}
721
722UINT8 SPC7110Decomp::probability(UINT32 n)
723{
724   return spc7110_evolution_table[m_context[n].index][0];
725}
726
727UINT8 SPC7110Decomp::next_lps(UINT32 n)
728{
729   return spc7110_evolution_table[m_context[n].index][1];
730}
731
732UINT8 SPC7110Decomp::next_mps(UINT32 n)
733{
734   return spc7110_evolution_table[m_context[n].index][2];
735}
736
737UINT8 SPC7110Decomp::toggle_invert(UINT32 n)
738{
739   return spc7110_evolution_table[m_context[n].index][3];
740}
741
742UINT32 SPC7110Decomp::morton_2x8(UINT32 data)
743{
744   //reverse morton lookup: de-interleave two 8-bit values
745   //15, 13, 11,  9,  7,  5,  3,  1 -> 15- 8
746   //14, 12, 10,  8,  6,  4,  2,  0 ->  7- 0
747   return m_morton16[0][(data >>  0) & 255] + m_morton16[1][(data >>  8) & 255];
748}
749
750UINT32 SPC7110Decomp::morton_4x8(UINT32 data)
751{
752   //reverse morton lookup: de-interleave four 8-bit values
753   //31, 27, 23, 19, 15, 11,  7,  3 -> 31-24
754   //30, 26, 22, 18, 14, 10,  6,  2 -> 23-16
755   //29, 25, 21, 17, 13,  9,  5,  1 -> 15- 8
756   //28, 24, 20, 16, 12,  8,  4,  0 ->  7- 0
757   return m_morton32[0][(data >>  0) & 255] + m_morton32[1][(data >>  8) & 255]
758      + m_morton32[2][(data >> 16) & 255] + m_morton32[3][(data >> 24) & 255];
759}
760
761static void spc7110_update_time(running_machine &machine, UINT8 offset);
762
763enum RTC_State
764{
765   RTCS_Inactive,
766   RTCS_ModeSelect,
767   RTCS_IndexSelect,
768   RTCS_Write
769};
770
771enum RTC_Mode
772{
773   RTCM_Linear = 0x03,
774   RTCM_Indexed = 0x0c
775};
776
777static const UINT32 spc7110_months[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
778
779struct snes_spc7110_t
780{
781   //==================
782   //decompression unit
783   //==================
784   UINT8 r4801;        // compression table low
785   UINT8 r4802;        // compression table high
786   UINT8 r4803;        // compression table bank
787   UINT8 r4804;        // compression table index
788   UINT8 r4805;        // decompression buffer index low
789   UINT8 r4806;        // decompression buffer index high
790   UINT8 r4807;        // ???
791   UINT8 r4808;        // ???
792   UINT8 r4809;        // compression length low
793   UINT8 r480a;        // compression length high
794   UINT8 r480b;        // decompression control register
795   UINT8 r480c;        // decompression status
796
797   SPC7110Decomp* decomp;
798
799   UINT8 r4811;        // data pointer low
800   UINT8 r4812;        // data pointer high
801   UINT8 r4813;        // data pointer bank
802   UINT8 r4814;        // data adjust low
803   UINT8 r4815;        // data adjust high
804   UINT8 r4816;        // data increment low
805   UINT8 r4817;        // data increment high
806   UINT8 r4818;        // data port control register
807
808   UINT8 r481x;
809
810   UINT8 r4814_latch;
811   UINT8 r4815_latch;
812
813   //=========
814   //math unit
815   //=========
816   UINT8 r4820;        // 16-bit multiplicand B0, 32-bit dividend B0
817   UINT8 r4821;        // 16-bit multiplicand B1, 32-bit dividend B1
818   UINT8 r4822;        // 32-bit dividend B2
819   UINT8 r4823;        // 32-bit dividend B3
820   UINT8 r4824;        // 16-bit multiplier B0
821   UINT8 r4825;        // 16-bit multiplier B1
822   UINT8 r4826;        // 16-bit divisor B0
823   UINT8 r4827;        // 16-bit divisor B1
824   UINT8 r4828;        // 32-bit product B0, 32-bit quotient B0
825   UINT8 r4829;        // 32-bit product B1, 32-bit quotient B1
826   UINT8 r482a;        // 32-bit product B2, 32-bit quotient B2
827   UINT8 r482b;        // 32-bit product B3, 32-bit quotient B3
828   UINT8 r482c;        // 16-bit remainder B0
829   UINT8 r482d;        // 16-bit remainder B1
830   UINT8 r482e;        // math control register
831   UINT8 r482f;        // math status
832
833   //===================
834   //memory mapping unit
835   //===================
836   UINT8 r4830;        // SRAM write enable
837   UINT8 r4831;        // $[d0-df]:[0000-ffff] mapping
838   UINT8 r4832;        // $[e0-ef]:[0000-ffff] mapping
839   UINT8 r4833;        // $[f0-ff]:[0000-ffff] mapping
840   UINT8 r4834;        // ???
841
842   UINT32 dx_offset;
843   UINT32 ex_offset;
844   UINT32 fx_offset;
845
846   //====================
847   //real-time clock unit
848   //====================
849   UINT8 r4840;        // RTC latch
850   UINT8 r4841;        // RTC index/data port
851   UINT8 r4842;        // RTC status
852
853   UINT32 rtc_state;
854   UINT32 rtc_mode;
855   UINT32 rtc_index;
856
857   UINT64 rtc_offset;
858
859   UINT8 rtc_ram[16];  // 0-12 secs, min, hrs, etc.; 13-14-15 control registers
860
861   UINT32 size;
862};
863
864static snes_spc7110_t snes_spc7110;
865
866void spc7110_init(running_machine& machine)
867{
868   snes_state *state = machine.driver_data<snes_state>();
869
870   snes_spc7110.r4801 = 0x00;
871   snes_spc7110.r4802 = 0x00;
872   snes_spc7110.r4803 = 0x00;
873   snes_spc7110.r4804 = 0x00;
874   snes_spc7110.r4805 = 0x00;
875   snes_spc7110.r4806 = 0x00;
876   snes_spc7110.r4807 = 0x00;
877   snes_spc7110.r4808 = 0x00;
878   snes_spc7110.r4809 = 0x00;
879   snes_spc7110.r480a = 0x00;
880   snes_spc7110.r480b = 0x00;
881   snes_spc7110.r480c = 0x00;
882
883   snes_spc7110.r4811 = 0x00;
884   snes_spc7110.r4812 = 0x00;
885   snes_spc7110.r4813 = 0x00;
886   snes_spc7110.r4814 = 0x00;
887   snes_spc7110.r4815 = 0x00;
888   snes_spc7110.r4816 = 0x00;
889   snes_spc7110.r4817 = 0x00;
890   snes_spc7110.r4818 = 0x00;
891
892   snes_spc7110.r481x = 0x00;
893   snes_spc7110.r4814_latch = 0;
894   snes_spc7110.r4815_latch = 0;
895
896   snes_spc7110.r4820 = 0x00;
897   snes_spc7110.r4821 = 0x00;
898   snes_spc7110.r4822 = 0x00;
899   snes_spc7110.r4823 = 0x00;
900   snes_spc7110.r4824 = 0x00;
901   snes_spc7110.r4825 = 0x00;
902   snes_spc7110.r4826 = 0x00;
903   snes_spc7110.r4827 = 0x00;
904   snes_spc7110.r4828 = 0x00;
905   snes_spc7110.r4829 = 0x00;
906   snes_spc7110.r482a = 0x00;
907   snes_spc7110.r482b = 0x00;
908   snes_spc7110.r482c = 0x00;
909   snes_spc7110.r482d = 0x00;
910   snes_spc7110.r482e = 0x00;
911   snes_spc7110.r482f = 0x00;
912
913   snes_spc7110.r4830 = 0x00;
914   spc7110_mmio_write(machine, 0x4831, 0);
915   spc7110_mmio_write(machine, 0x4832, 1);
916   spc7110_mmio_write(machine, 0x4833, 2);
917   snes_spc7110.r4834 = 0x00;
918
919   snes_spc7110.r4840 = 0x00;
920   snes_spc7110.r4841 = 0x00;
921   snes_spc7110.r4842 = 0x00;
922
923   snes_spc7110.size = state->m_cart_size;
924
925   snes_spc7110.decomp = auto_alloc(machine, SPC7110Decomp(machine, snes_spc7110.size));
926}
927
928void spc7110rtc_init(running_machine& machine)
929{
930   spc7110_init(machine);
931
932   snes_spc7110.rtc_state = RTCS_Inactive;
933   snes_spc7110.rtc_mode  = RTCM_Linear;
934   snes_spc7110.rtc_index = 0;
935
936   snes_spc7110.rtc_offset = 0;
937
938   spc7110_update_time(machine, 0);
939}
940
941static UINT32 spc7110_datarom_addr(UINT32 addr)
942{
943   UINT32 size = snes_spc7110.size - 0x100000;
944   while (addr >= size)
945   {
946      addr -= size;
947   }
948   return addr + 0x100000;
949}
950
951static UINT32 spc7110_data_pointer(void)
952{
953   return snes_spc7110.r4811 + (snes_spc7110.r4812 << 8) + (snes_spc7110.r4813 << 16);
954}
955
956static UINT32 spc7110_data_adjust(void)
957{
958   return snes_spc7110.r4814 + (snes_spc7110.r4815 << 8);
959}
960
961static UINT32 spc7110_data_increment(void)
962{
963   return snes_spc7110.r4816 + (snes_spc7110.r4817 << 8);
964}
965
966static void spc7110_set_data_pointer(UINT32 addr)
967{
968   snes_spc7110.r4811 = addr;
969   snes_spc7110.r4812 = addr >> 8;
970   snes_spc7110.r4813 = addr >> 16;
971}
972
973static void spc7110_set_data_adjust(UINT32 addr)
974{
975   snes_spc7110.r4814 = addr;
976   snes_spc7110.r4815 = addr >> 8;
977}
978
979// FIXME: SPC7110 RTC is capable of rounding/adding/zero-ing seconds, so
980// we should probably keep track internally of the time rather than updating
981// to the system time at each call with a "offset" tracking as we do now...
982// (and indeed current code fails to pass Tengai Makyou Zero tests)
983static void spc7110_update_time(running_machine &machine, UINT8 offset)
984{
985   system_time curtime, *systime = &curtime;
986   machine.current_datetime(curtime);
987   int update = 1;
988
989   snes_spc7110.rtc_offset += offset;
990
991   // TEST: can we go beyond 24hrs of rounding?!? I doubt it will ever go beyond 3600, but I could be wrong...
992   assert(snes_spc7110.rtc_offset < 86400);
993
994   /* do not update if CR0 or CR2 timer disable flags are set */
995   if ((snes_spc7110.rtc_ram[13] & 0x01) || (snes_spc7110.rtc_ram[15] & 0x03))
996      update = 0;
997
998   if (update)
999   {
1000      /* update time with offset, assuming offset < 3600s */
1001      UINT8 second = systime->local_time.second;
1002      UINT8 minute = systime->local_time.minute;
1003      UINT8 hour = systime->local_time.hour;
1004      UINT8 mday = systime->local_time.mday;
1005
1006      while (snes_spc7110.rtc_offset >= 3600)
1007      {
1008         snes_spc7110.rtc_offset -= 3600;
1009         hour++;
1010
1011         if (hour == 24)
1012         {
1013            mday++;
1014            hour = 0;
1015         }
1016      }
1017
1018      while (snes_spc7110.rtc_offset >= 60)
1019      {
1020         snes_spc7110.rtc_offset -= 60;
1021         minute++;
1022
1023         if (minute == 60)
1024         {
1025            hour++;
1026            minute = 0;
1027         }
1028      }
1029
1030      while (snes_spc7110.rtc_offset)
1031      {
1032         snes_spc7110.rtc_offset -= 1;
1033         second++;
1034
1035         if (second == 60)
1036         {
1037            minute++;
1038            second = 0;
1039         }
1040      }
1041
1042      snes_spc7110.rtc_ram[0] = second % 10;
1043      snes_spc7110.rtc_ram[1] = second / 10;
1044      snes_spc7110.rtc_ram[2] = minute % 10;
1045      snes_spc7110.rtc_ram[3] = minute / 10;
1046      snes_spc7110.rtc_ram[4] = hour % 10;
1047      snes_spc7110.rtc_ram[5] = hour / 10;
1048      snes_spc7110.rtc_ram[6] = mday % 10;
1049      snes_spc7110.rtc_ram[7] = mday / 10;
1050      snes_spc7110.rtc_ram[8] = systime->local_time.month % 10;
1051      snes_spc7110.rtc_ram[9] = systime->local_time.month / 10;
1052      snes_spc7110.rtc_ram[8] = systime->local_time.month;
1053      snes_spc7110.rtc_ram[10] = (systime->local_time.year - 1900) % 10;
1054      snes_spc7110.rtc_ram[11] = ((systime->local_time.year - 1900) / 10) % 10;
1055      snes_spc7110.rtc_ram[12] = systime->local_time.weekday % 7;
1056   }
1057}
1058
1059UINT8 spc7110_mmio_read(address_space &space, UINT32 addr)
1060{
1061   running_machine &machine = space.machine();
1062   UINT8 *ROM = machine.root_device().memregion("cart")->base();
1063
1064   addr &= 0xffff;
1065
1066   switch(addr)
1067   {
1068   //==================
1069   //decompression unit
1070   //==================
1071
1072   case 0x4800:
1073      {
1074         UINT16 counter = (snes_spc7110.r4809 + (snes_spc7110.r480a << 8));
1075         counter--;
1076         snes_spc7110.r4809 = counter;
1077         snes_spc7110.r480a = counter >> 8;
1078         return snes_spc7110.decomp->read(ROM);
1079      }
1080   case 0x4801: return snes_spc7110.r4801;
1081   case 0x4802: return snes_spc7110.r4802;
1082   case 0x4803: return snes_spc7110.r4803;
1083   case 0x4804: return snes_spc7110.r4804;
1084   case 0x4805: return snes_spc7110.r4805;
1085   case 0x4806: return snes_spc7110.r4806;
1086   case 0x4807: return snes_spc7110.r4807;
1087   case 0x4808: return snes_spc7110.r4808;
1088   case 0x4809: return snes_spc7110.r4809;
1089   case 0x480a: return snes_spc7110.r480a;
1090   case 0x480b: return snes_spc7110.r480b;
1091   case 0x480c:
1092      {
1093         UINT8 status = snes_spc7110.r480c;
1094         snes_spc7110.r480c &= 0x7f;
1095         return status;
1096      }
1097
1098   //==============
1099   //data port unit
1100   //==============
1101
1102   case 0x4810:
1103      {
1104         UINT8 data;
1105         UINT32 address, adjust, adjustaddr;
1106
1107         if (snes_spc7110.r481x != 0x07) return 0x00;
1108
1109         address = spc7110_data_pointer();
1110         adjust = spc7110_data_adjust();
1111         if (snes_spc7110.r4818 & 8)
1112         {
1113            adjust = (INT16)adjust;  //16-bit sign extend
1114         }
1115
1116         adjustaddr = address;
1117         if (snes_spc7110.r4818 & 2)
1118         {
1119            adjustaddr += adjust;
1120            spc7110_set_data_adjust(adjust + 1);
1121         }
1122
1123         data = ROM[spc7110_datarom_addr(adjustaddr)];
1124         if (!(snes_spc7110.r4818 & 2))
1125         {
1126            UINT32 increment = (snes_spc7110.r4818 & 1) ? spc7110_data_increment() : 1;
1127            if (snes_spc7110.r4818 & 4)
1128            {
1129               increment = (INT16)increment;  //16-bit sign extend
1130            }
1131
1132            if ((snes_spc7110.r4818 & 16) == 0)
1133            {
1134               spc7110_set_data_pointer(address + increment);
1135            }
1136            else
1137            {
1138               spc7110_set_data_adjust(adjust + increment);
1139            }
1140         }
1141
1142         return data;
1143      }
1144   case 0x4811: return snes_spc7110.r4811;
1145   case 0x4812: return snes_spc7110.r4812;
1146   case 0x4813: return snes_spc7110.r4813;
1147   case 0x4814: return snes_spc7110.r4814;
1148   case 0x4815: return snes_spc7110.r4815;
1149   case 0x4816: return snes_spc7110.r4816;
1150   case 0x4817: return snes_spc7110.r4817;
1151   case 0x4818: return snes_spc7110.r4818;
1152   case 0x481a:
1153      {
1154         UINT8 data;
1155         UINT32 address, adjust;
1156         if (snes_spc7110.r481x != 0x07)
1157         {
1158            return 0x00;
1159         }
1160
1161         address = spc7110_data_pointer();
1162         adjust = spc7110_data_adjust();
1163         if (snes_spc7110.r4818 & 8)
1164         {
1165            adjust = (INT16)adjust;  //16-bit sign extend
1166         }
1167
1168         data = ROM[spc7110_datarom_addr(address + adjust)];
1169         if ((snes_spc7110.r4818 & 0x60) == 0x60)
1170         {
1171            if ((snes_spc7110.r4818 & 16) == 0)
1172            {
1173               spc7110_set_data_pointer(address + adjust);
1174            }
1175            else
1176            {
1177               spc7110_set_data_adjust(adjust + adjust);
1178            }
1179         }
1180
1181         return data;
1182      }
1183
1184   //=========
1185   //math unit
1186   //=========
1187
1188   case 0x4820: return snes_spc7110.r4820;
1189   case 0x4821: return snes_spc7110.r4821;
1190   case 0x4822: return snes_spc7110.r4822;
1191   case 0x4823: return snes_spc7110.r4823;
1192   case 0x4824: return snes_spc7110.r4824;
1193   case 0x4825: return snes_spc7110.r4825;
1194   case 0x4826: return snes_spc7110.r4826;
1195   case 0x4827: return snes_spc7110.r4827;
1196   case 0x4828: return snes_spc7110.r4828;
1197   case 0x4829: return snes_spc7110.r4829;
1198   case 0x482a: return snes_spc7110.r482a;
1199   case 0x482b: return snes_spc7110.r482b;
1200   case 0x482c: return snes_spc7110.r482c;
1201   case 0x482d: return snes_spc7110.r482d;
1202   case 0x482e: return snes_spc7110.r482e;
1203   case 0x482f:
1204      {
1205         UINT8 status = snes_spc7110.r482f;
1206         snes_spc7110.r482f &= 0x7f;
1207         return status;
1208      }
1209
1210   //===================
1211   //memory mapping unit
1212   //===================
1213
1214   case 0x4830: return snes_spc7110.r4830;
1215   case 0x4831: return snes_spc7110.r4831;
1216   case 0x4832: return snes_spc7110.r4832;
1217   case 0x4833: return snes_spc7110.r4833;
1218   case 0x4834: return snes_spc7110.r4834;
1219
1220   //====================
1221   //real-time clock unit
1222   //====================
1223   case 0x4840: return snes_spc7110.r4840;
1224   case 0x4841:
1225      {
1226         UINT8 data = 0;
1227         if (snes_spc7110.rtc_state == RTCS_Inactive || snes_spc7110.rtc_state == RTCS_ModeSelect)
1228            return 0x00;
1229
1230         snes_spc7110.r4842 = 0x80;
1231         data = snes_spc7110.rtc_ram[snes_spc7110.rtc_index];
1232         snes_spc7110.rtc_index = (snes_spc7110.rtc_index + 1) & 15;
1233         return data;
1234      }
1235   case 0x4842:
1236      {
1237         UINT8 status = snes_spc7110.r4842;
1238         snes_spc7110.r4842 &= 0x7f;
1239         return status;
1240      }
1241   }
1242
1243   return snes_open_bus_r(space, 0);
1244}
1245
1246void spc7110_mmio_write(running_machine &machine, UINT32 addr, UINT8 data)
1247{
1248   UINT8 *ROM = machine.root_device().memregion("cart")->base();
1249
1250   addr &= 0xffff;
1251
1252   switch(addr)
1253   {
1254   //==================
1255   //decompression unit
1256   //==================
1257
1258   case 0x4801: snes_spc7110.r4801 = data; break;
1259   case 0x4802: snes_spc7110.r4802 = data; break;
1260   case 0x4803: snes_spc7110.r4803 = data; break;
1261   case 0x4804: snes_spc7110.r4804 = data; break;
1262   case 0x4805: snes_spc7110.r4805 = data; break;
1263   case 0x4806:
1264      {
1265         UINT32 table, index, address, mode, offset;
1266         snes_spc7110.r4806 = data;
1267
1268         table   = (snes_spc7110.r4801 + (snes_spc7110.r4802 << 8) + (snes_spc7110.r4803 << 16));
1269         index   = (snes_spc7110.r4804 << 2);
1270         //length  = (snes_spc7110.r4809 + (snes_spc7110.r480a << 8));
1271         address = spc7110_datarom_addr(table + index);
1272         mode    = (ROM[address + 0]);
1273         offset  = (ROM[address + 1] << 16)
1274               + (ROM[address + 2] <<  8)
1275               + (ROM[address + 3] <<  0);
1276
1277         snes_spc7110.decomp->init(machine, ROM, mode, offset, (snes_spc7110.r4805 + (snes_spc7110.r4806 << 8)) << mode);
1278         snes_spc7110.r480c = 0x80;
1279      }
1280      break;
1281
1282   case 0x4807: snes_spc7110.r4807 = data; break;
1283   case 0x4808: snes_spc7110.r4808 = data; break;
1284   case 0x4809: snes_spc7110.r4809 = data; break;
1285   case 0x480a: snes_spc7110.r480a = data; break;
1286   case 0x480b: snes_spc7110.r480b = data; break;
1287
1288   //==============
1289   //data port unit
1290   //==============
1291
1292   case 0x4811: snes_spc7110.r4811 = data; snes_spc7110.r481x |= 0x01; break;
1293   case 0x4812: snes_spc7110.r4812 = data; snes_spc7110.r481x |= 0x02; break;
1294   case 0x4813: snes_spc7110.r4813 = data; snes_spc7110.r481x |= 0x04; break;
1295   case 0x4814:
1296      {
1297         snes_spc7110.r4814 = data;
1298         snes_spc7110.r4814_latch = 1;
1299         if (!snes_spc7110.r4815_latch)
1300         {
1301            break;
1302         }
1303         if (!(snes_spc7110.r4818 & 2))
1304         {
1305            break;
1306         }
1307         if (snes_spc7110.r4818 & 0x10)
1308         {
1309            break;
1310         }
1311
1312         if ((snes_spc7110.r4818 & 0x60) == 0x20)
1313         {
1314            UINT32 increment = spc7110_data_adjust() & 0xff;
1315            if (snes_spc7110.r4818 & 8)
1316            {
1317               increment = (INT8)increment;  //8-bit sign extend
1318            }
1319            spc7110_set_data_pointer(spc7110_data_pointer() + increment);
1320         }
1321         else if ((snes_spc7110.r4818 & 0x60) == 0x40)
1322         {
1323            UINT32 increment = spc7110_data_adjust();
1324            if (snes_spc7110.r4818 & 8)
1325            {
1326               increment = (INT16)increment;  //16-bit sign extend
1327            }
1328            spc7110_set_data_pointer(spc7110_data_pointer() + increment);
1329         }
1330         break;
1331      }
1332
1333   case 0x4815:
1334      {
1335         snes_spc7110.r4815 = data;
1336         snes_spc7110.r4815_latch = 1;
1337         if (!snes_spc7110.r4814_latch)
1338         {
1339            break;
1340         }
1341         if (!(snes_spc7110.r4818 & 2))
1342         {
1343            break;
1344         }
1345         if (snes_spc7110.r4818 & 0x10)
1346         {
1347            break;
1348         }
1349
1350         if ((snes_spc7110.r4818 & 0x60) == 0x20)
1351         {
1352            UINT32 increment = spc7110_data_adjust() & 0xff;
1353            if (snes_spc7110.r4818 & 8)
1354            {
1355               increment = (INT8)increment;  //8-bit sign extend
1356            }
1357            spc7110_set_data_pointer(spc7110_data_pointer() + increment);
1358         }
1359         else if ((snes_spc7110.r4818 & 0x60) == 0x40)
1360         {
1361            UINT32 increment = spc7110_data_adjust();
1362            if (snes_spc7110.r4818 & 8)
1363            {
1364               increment = (INT16)increment;  //16-bit sign extend
1365            }
1366            spc7110_set_data_pointer(spc7110_data_pointer() + increment);
1367         }
1368         break;
1369      }
1370
1371   case 0x4816: snes_spc7110.r4816 = data; break;
1372   case 0x4817: snes_spc7110.r4817 = data; break;
1373   case 0x4818:
1374      {
1375            if (snes_spc7110.r481x != 0x07)
1376            break;
1377
1378            snes_spc7110.r4818 = data;
1379            snes_spc7110.r4814_latch = snes_spc7110.r4815_latch = 0;
1380            break;
1381         }
1382
1383   //=========
1384   //math unit
1385   //=========
1386
1387   case 0x4820: snes_spc7110.r4820 = data; break;
1388   case 0x4821: snes_spc7110.r4821 = data; break;
1389   case 0x4822: snes_spc7110.r4822 = data; break;
1390   case 0x4823: snes_spc7110.r4823 = data; break;
1391   case 0x4824: snes_spc7110.r4824 = data; break;
1392   case 0x4825:
1393      {
1394            snes_spc7110.r4825 = data;
1395
1396            if (snes_spc7110.r482e & 1)
1397         {
1398               //signed 16-bit x 16-bit multiplication
1399               INT16 r0 = (INT16)(snes_spc7110.r4824 + (snes_spc7110.r4825 << 8));
1400               INT16 r1 = (INT16)(snes_spc7110.r4820 + (snes_spc7110.r4821 << 8));
1401
1402               INT32 result = r0 * r1;
1403               snes_spc7110.r4828 = result;
1404               snes_spc7110.r4829 = result >> 8;
1405               snes_spc7110.r482a = result >> 16;
1406               snes_spc7110.r482b = result >> 24;
1407         }
1408         else
1409         {
1410               //unsigned 16-bit x 16-bit multiplication
1411               UINT16 r0 = (UINT16)(snes_spc7110.r4824 + (snes_spc7110.r4825 << 8));
1412               UINT16 r1 = (UINT16)(snes_spc7110.r4820 + (snes_spc7110.r4821 << 8));
1413
1414               UINT32 result = r0 * r1;
1415               snes_spc7110.r4828 = result;
1416               snes_spc7110.r4829 = result >> 8;
1417               snes_spc7110.r482a = result >> 16;
1418               snes_spc7110.r482b = result >> 24;
1419         }
1420
1421         snes_spc7110.r482f = 0x80;
1422         break;
1423      }
1424
1425   case 0x4826: snes_spc7110.r4826 = data; break;
1426   case 0x4827:
1427      {
1428         snes_spc7110.r4827 = data;
1429
1430         if (snes_spc7110.r482e & 1)
1431         {
1432            //signed 32-bit x 16-bit division
1433            INT32 dividend = (INT32)(snes_spc7110.r4820 + (snes_spc7110.r4821 << 8) + (snes_spc7110.r4822 << 16) + (snes_spc7110.r4823 << 24));
1434            INT16 divisor  = (INT16)(snes_spc7110.r4826 + (snes_spc7110.r4827 << 8));
1435
1436            INT32 quotient;
1437            INT16 remainder;
1438
1439            if (divisor)
1440            {
1441               quotient  = (INT32)(dividend / divisor);
1442               remainder = (INT32)(dividend % divisor);
1443            }
1444            else
1445            {
1446               //illegal division by zero
1447               quotient  = 0;
1448               remainder = dividend & 0xffff;
1449            }
1450
1451            snes_spc7110.r4828 = quotient;
1452            snes_spc7110.r4829 = quotient >> 8;
1453            snes_spc7110.r482a = quotient >> 16;
1454            snes_spc7110.r482b = quotient >> 24;
1455
1456            snes_spc7110.r482c = remainder;
1457            snes_spc7110.r482d = remainder >> 8;
1458         }
1459         else
1460         {
1461            //unsigned 32-bit x 16-bit division
1462            UINT32 dividend = (UINT32)(snes_spc7110.r4820 + (snes_spc7110.r4821 << 8) + (snes_spc7110.r4822 << 16) + (snes_spc7110.r4823 << 24));
1463            UINT16 divisor  = (UINT16)(snes_spc7110.r4826 + (snes_spc7110.r4827 << 8));
1464
1465            UINT32 quotient;
1466            UINT16 remainder;
1467
1468            if (divisor)
1469            {
1470               quotient  = (UINT32)(dividend / divisor);
1471               remainder = (UINT16)(dividend % divisor);
1472            }
1473            else
1474            {
1475               //illegal division by zero
1476               quotient  = 0;
1477               remainder = dividend & 0xffff;
1478            }
1479
1480            snes_spc7110.r4828 = quotient;
1481            snes_spc7110.r4829 = quotient >> 8;
1482            snes_spc7110.r482a = quotient >> 16;
1483            snes_spc7110.r482b = quotient >> 24;
1484
1485            snes_spc7110.r482c = remainder;
1486            snes_spc7110.r482d = remainder >> 8;
1487         }
1488
1489         snes_spc7110.r482f = 0x80;
1490         break;
1491      }
1492
1493   case 0x482e:
1494      {
1495         //reset math unit
1496         snes_spc7110.r4820 = snes_spc7110.r4821 = snes_spc7110.r4822 = snes_spc7110.r4823 = 0;
1497         snes_spc7110.r4824 = snes_spc7110.r4825 = snes_spc7110.r4826 = snes_spc7110.r4827 = 0;
1498         snes_spc7110.r4828 = snes_spc7110.r4829 = snes_spc7110.r482a = snes_spc7110.r482b = 0;
1499         snes_spc7110.r482c = snes_spc7110.r482d = 0;
1500
1501         snes_spc7110.r482e = data;
1502         break;
1503      }
1504
1505   //===================
1506   //memory mapping unit
1507   //===================
1508
1509   case 0x4830: snes_spc7110.r4830 = data; break;
1510
1511   case 0x4831:
1512      {
1513         snes_spc7110.r4831 = data;
1514         snes_spc7110.dx_offset = spc7110_datarom_addr(data * 0x100000);
1515         break;
1516      }
1517
1518   case 0x4832:
1519      {
1520         snes_spc7110.r4832 = data;
1521         snes_spc7110.ex_offset = spc7110_datarom_addr(data * 0x100000);
1522         break;
1523      }
1524
1525   case 0x4833:
1526      {
1527         snes_spc7110.r4833 = data;
1528         snes_spc7110.fx_offset = spc7110_datarom_addr(data * 0x100000);
1529         break;
1530      }
1531
1532   case 0x4834: snes_spc7110.r4834 = data; break;
1533
1534   //====================
1535   //real-time clock unit
1536   //====================
1537
1538   case 0x4840:
1539      {
1540         snes_spc7110.r4840 = data;
1541
1542         if (!(snes_spc7110.r4840 & 1))
1543         {
1544            //disable RTC
1545            snes_spc7110.rtc_state = RTCS_Inactive;
1546            spc7110_update_time(machine, 0);
1547         }
1548         else
1549         {
1550            //enable RTC
1551            snes_spc7110.r4842 = 0x80;
1552            snes_spc7110.rtc_state = RTCS_ModeSelect;
1553         }
1554      }
1555      break;
1556
1557   case 0x4841:
1558      {
1559         snes_spc7110.r4841 = data;
1560
1561         switch (snes_spc7110.rtc_state)
1562         {
1563         case RTCS_ModeSelect:
1564            if (data == RTCM_Linear || data == RTCM_Indexed)
1565            {
1566               snes_spc7110.r4842 = 0x80;
1567               snes_spc7110.rtc_state = RTCS_IndexSelect;
1568               snes_spc7110.rtc_mode = (RTC_Mode)data;
1569               snes_spc7110.rtc_index = 0;
1570            }
1571            break;
1572
1573         case RTCS_IndexSelect:
1574            snes_spc7110.r4842 = 0x80;
1575            snes_spc7110.rtc_index = data & 15;
1576            if (snes_spc7110.rtc_mode == RTCM_Linear)
1577               snes_spc7110.rtc_state = RTCS_Write;
1578            break;
1579
1580         case RTCS_Write:
1581            snes_spc7110.r4842 = 0x80;
1582
1583            //control register 0
1584            if (snes_spc7110.rtc_index == 13)
1585            {
1586               //increment second counter
1587               if (data & 2)
1588                  spc7110_update_time(machine, 1);
1589
1590               //round minute counter
1591               if (data & 8)
1592               {
1593                  spc7110_update_time(machine, 0);
1594
1595                  UINT8 second = snes_spc7110.rtc_ram[0] + snes_spc7110.rtc_ram[1] * 10;
1596                  //clear seconds
1597                  snes_spc7110.rtc_ram[0] = 0;
1598                  snes_spc7110.rtc_ram[1] = 0;
1599
1600                  if (second >= 30)
1601                     spc7110_update_time(machine, 60);
1602               }
1603            }
1604
1605            //control register 2
1606            if (snes_spc7110.rtc_index == 15)
1607            {
1608               //disable timer and clear second counter
1609               if ((data & 1) && !(snes_spc7110.rtc_ram[15]  & 1))
1610               {
1611                  spc7110_update_time(machine, 0);
1612
1613                  //clear seconds
1614                  snes_spc7110.rtc_ram[0] = 0;
1615                  snes_spc7110.rtc_ram[1] = 0;
1616               }
1617
1618               //disable timer
1619               if ((data & 2) && !(snes_spc7110.rtc_ram[15] & 2))
1620                  spc7110_update_time(machine, 0);
1621            }
1622
1623            snes_spc7110.rtc_ram[snes_spc7110.rtc_index] = data & 15;
1624            snes_spc7110.rtc_index = (snes_spc7110.rtc_index + 1) & 15;
1625            break;
1626         }
1627      }
1628      break;
1629   }
1630}
1631
1632UINT8 spc7110_bank7_read(address_space &space, UINT32 offset)
1633{
1634   UINT8 *ROM = space.machine().root_device().memregion("cart")->base();
1635   UINT32 addr = offset & 0x0fffff;
1636
1637   switch (offset & 0xf00000)
1638   {
1639   case 0x100000:
1640      return ROM[snes_spc7110.dx_offset + addr];
1641   case 0x200000:
1642      return ROM[snes_spc7110.ex_offset + addr];
1643   case 0x300000:
1644      return ROM[snes_spc7110.fx_offset + addr];
1645   default:
1646      break;
1647   }
1648   return snes_open_bus_r(space, 0);
1649}
trunk/src/mame/machine/cx4ops.c
r21589r21590
1/***************************************************************************
2
3    cx4ops.c
4
5    Code based on original work by zsKnight, anomie and Nach.
6    This implementation is based on C++ "cx4*.cpp" by byuu
7    (up to date with source v 0.49).
8
9***************************************************************************/
10
11//Sprite Functions
12static void CX4_op00(running_machine& machine)
13{
14   switch(cx4.reg[0x4d])
15   {
16      case 0x00: CX4_op00_00(machine); break;
17      case 0x03: CX4_op00_03(); break;
18      case 0x05: CX4_op00_05(machine); break;
19      case 0x07: CX4_op00_07(); break;
20      case 0x08: CX4_op00_08(machine); break;
21      case 0x0b: CX4_op00_0b(machine); break;
22      case 0x0c: CX4_op00_0c(machine); break;
23   }
24}
25
26//Draw Wireframe
27static void CX4_op01(running_machine& machine)
28{
29   memset(cx4.ram + 0x300, 0, 2304);
30   CX4_C4DrawWireFrame(machine);
31}
32
33//Propulsion
34static void CX4_op05(running_machine &machine)
35{
36   INT32 temp = 0x10000;
37   if(CX4_readw(0x1f83))
38   {
39      temp = CX4_sar((temp / CX4_readw(0x1f83)) * CX4_readw(0x1f81), 8);
40   }
41   CX4_writew(machine, 0x1f80, temp);
42}
43
44//Set Vector length
45static void CX4_op0d(running_machine &machine)
46{
47   cx4.C41FXVal    = CX4_readw(0x1f80);
48   cx4.C41FYVal    = CX4_readw(0x1f83);
49   cx4.C41FDistVal = CX4_readw(0x1f86);
50   cx4.tanval = sqrt(((double)cx4.C41FYVal) * ((double)cx4.C41FYVal) + ((double)cx4.C41FXVal) * ((double)cx4.C41FXVal));
51   cx4.tanval = (double)cx4.C41FDistVal / cx4.tanval;
52   cx4.C41FYVal = (INT16)(((double)cx4.C41FYVal * cx4.tanval) * 0.99);
53   cx4.C41FXVal = (INT16)(((double)cx4.C41FXVal * cx4.tanval) * 0.98);
54   CX4_writew(machine, 0x1f89, cx4.C41FXVal);
55   CX4_writew(machine, 0x1f8c, cx4.C41FYVal);
56}
57
58//Triangle
59static void CX4_op10(void)
60{
61   cx4.r0 = CX4_ldr(0);
62   cx4.r1 = CX4_ldr(1);
63
64   cx4.r4 = cx4.r0 & 0x1ff;
65   if(cx4.r1 & 0x8000)
66   {
67      cx4.r1 |= ~0x7fff;
68   }
69
70   CX4_mul(CX4_cos(cx4.r4), cx4.r1, &cx4.r5, &cx4.r2);
71   cx4.r5 = (cx4.r5 >> 16) & 0xff;
72   cx4.r2 = (cx4.r2 << 8) + cx4.r5;
73
74   CX4_mul(CX4_sin(cx4.r4), cx4.r1, &cx4.r5, &cx4.r3);
75   cx4.r5 = (cx4.r5 >> 16) & 0xff;
76   cx4.r3 = (cx4.r3 << 8) + cx4.r5;
77
78   CX4_str(0, cx4.r0);
79   CX4_str(1, cx4.r1);
80   CX4_str(2, cx4.r2);
81   CX4_str(3, cx4.r3);
82   CX4_str(4, cx4.r4);
83   CX4_str(5, cx4.r5);
84}
85
86//Triangle
87static void CX4_op13(void)
88{
89   cx4.r0 = CX4_ldr(0);
90   cx4.r1 = CX4_ldr(1);
91
92   cx4.r4 = cx4.r0 & 0x1ff;
93
94   CX4_mul(CX4_cos(cx4.r4), cx4.r1, &cx4.r5, &cx4.r2);
95   cx4.r5 = (cx4.r5 >> 8) & 0xffff;
96   cx4.r2 = (cx4.r2 << 16) + cx4.r5;
97
98   CX4_mul(CX4_sin(cx4.r4), cx4.r1, &cx4.r5, &cx4.r3);
99   cx4.r5 = (cx4.r5 >> 8) & 0xffff;
100   cx4.r3 = (cx4.r3 << 16) + cx4.r5;
101
102   CX4_str(0, cx4.r0);
103   CX4_str(1, cx4.r1);
104   CX4_str(2, cx4.r2);
105   CX4_str(3, cx4.r3);
106   CX4_str(4, cx4.r4);
107   CX4_str(5, cx4.r5);
108}
109
110//Pythagorean
111static void CX4_op15(running_machine &machine)
112{
113   double temp = 0.0;
114   cx4.C41FXVal = CX4_readw(0x1f80);
115   cx4.C41FYVal = CX4_readw(0x1f83);
116   temp = sqrt((double)cx4.C41FXVal * (double)cx4.C41FXVal + (double)cx4.C41FYVal * (double)cx4.C41FYVal);
117   cx4.C41FDist = (INT16)temp;
118   CX4_writew(machine, 0x1f80, cx4.C41FDist);
119}
120
121//Calculate distance
122static void CX4_op1f(running_machine &machine)
123{
124   cx4.C41FXVal = CX4_readw(0x1f80);
125   cx4.C41FYVal = CX4_readw(0x1f83);
126   if(!cx4.C41FXVal)
127   {
128      cx4.C41FAngleRes = (cx4.C41FYVal > 0) ? 0x080 : 0x180;
129   }
130   else
131   {
132      cx4.tanval = ((double)cx4.C41FYVal) / ((double)cx4.C41FXVal);
133      cx4.C41FAngleRes = (INT16)(atan(cx4.tanval) / (PI * 2) * 512);
134      cx4.C41FAngleRes = cx4.C41FAngleRes;
135      if(cx4.C41FXVal < 0)
136      {
137         cx4.C41FAngleRes += 0x100;
138      }
139      cx4.C41FAngleRes &= 0x1ff;
140   }
141   CX4_writew(machine, 0x1f86, cx4.C41FAngleRes);
142}
143
144//Trapezoid
145static void CX4_op22(void)
146{
147   INT16 angle1 = CX4_readw(0x1f8c) & 0x1ff;
148   INT16 angle2 = CX4_readw(0x1f8f) & 0x1ff;
149   INT32 tan1 = CX4_Tan(angle1);
150   INT32 tan2 = CX4_Tan(angle2);
151   INT16 y = CX4_readw(0x1f83) - CX4_readw(0x1f89);
152   INT16 left, right;
153   INT32 j;
154
155   for(j = 0; j < 225; j++, y++)
156   {
157      if(y >= 0)
158      {
159         left  = CX4_sar((INT32)tan1 * y, 16) - CX4_readw(0x1f80) + CX4_readw(0x1f86);
160         right = CX4_sar((INT32)tan2 * y, 16) - CX4_readw(0x1f80) + CX4_readw(0x1f86) + CX4_readw(0x1f93);
161
162         if(left < 0 && right < 0)
163         {
164            left  = 1;
165            right = 0;
166         }
167         else if(left < 0)
168         {
169            left  = 0;
170         }
171         else if(right < 0)
172         {
173            right = 0;
174         }
175
176         if(left > 255 && right > 255)
177         {
178            left  = 255;
179            right = 254;
180         }
181         else if(left > 255)
182         {
183            left  = 255;
184         }
185         else if(right > 255)
186         {
187            right = 255;
188         }
189      }
190      else
191      {
192         left  = 1;
193         right = 0;
194      }
195      cx4.ram[j + 0x800] = (UINT8)left;
196      cx4.ram[j + 0x900] = (UINT8)right;
197   }
198}
199
200//Multiply
201static void CX4_op25(void)
202{
203   cx4.r0 = CX4_ldr(0);
204   cx4.r1 = CX4_ldr(1);
205   CX4_mul(cx4.r0, cx4.r1, &cx4.r0, &cx4.r1);
206   CX4_str(0, cx4.r0);
207   CX4_str(1, cx4.r1);
208}
209
210//Transform Coords
211static void CX4_op2d(running_machine &machine)
212{
213   cx4.C4WFXVal  = CX4_readw(0x1f81);
214   cx4.C4WFYVal  = CX4_readw(0x1f84);
215   cx4.C4WFZVal  = CX4_readw(0x1f87);
216   cx4.C4WFX2Val = CX4_read (0x1f89);
217   cx4.C4WFY2Val = CX4_read (0x1f8a);
218   cx4.C4WFDist  = CX4_read (0x1f8b);
219   cx4.C4WFScale = CX4_readw(0x1f90);
220   CX4_C4TransfWireFrame2();
221   CX4_writew(machine, 0x1f80, cx4.C4WFXVal);
222   CX4_writew(machine, 0x1f83, cx4.C4WFYVal);
223}
224
225//Sum
226static void CX4_op40(void)
227{
228   UINT32 i;
229   cx4.r0 = 0;
230   for(i=0;i<0x800;i++)
231   {
232      cx4.r0 += cx4.ram[i];
233   }
234   CX4_str(0, cx4.r0);
235}
236
237//Square
238static void CX4_op54(void)
239{
240   cx4.r0 = CX4_ldr(0);
241   CX4_mul(cx4.r0, cx4.r0, &cx4.r1, &cx4.r2);
242   CX4_str(1, cx4.r1);
243   CX4_str(2, cx4.r2);
244}
245
246//Immediate Register
247static void CX4_op5c(void)
248{
249   CX4_str(0, 0x000000);
250   CX4_immediate_reg(0);
251}
252
253//Immediate Register (Multiple)
254static void CX4_op5e(void) { CX4_immediate_reg( 0); }
255static void CX4_op60(void) { CX4_immediate_reg( 3); }
256static void CX4_op62(void) { CX4_immediate_reg( 6); }
257static void CX4_op64(void) { CX4_immediate_reg( 9); }
258static void CX4_op66(void) { CX4_immediate_reg(12); }
259static void CX4_op68(void) { CX4_immediate_reg(15); }
260static void CX4_op6a(void) { CX4_immediate_reg(18); }
261static void CX4_op6c(void) { CX4_immediate_reg(21); }
262static void CX4_op6e(void) { CX4_immediate_reg(24); }
263static void CX4_op70(void) { CX4_immediate_reg(27); }
264static void CX4_op72(void) { CX4_immediate_reg(30); }
265static void CX4_op74(void) { CX4_immediate_reg(33); }
266static void CX4_op76(void) { CX4_immediate_reg(36); }
267static void CX4_op78(void) { CX4_immediate_reg(39); }
268static void CX4_op7a(void) { CX4_immediate_reg(42); }
269static void CX4_op7c(void) { CX4_immediate_reg(45); }
270
271//Immediate ROM
272static void CX4_op89(void)
273{
274   CX4_str(0, 0x054336);
275   CX4_str(1, 0xffffff);
276}
trunk/src/mame/machine/snes.c
r21589r21590
3333
3434struct snes_cart_info snes_cart;
3535
36#define DMA_REG(a) m_dma_regs[a - 0x4300]   // regs 0x4300-0x437f
36#define DMA_REG(a) m_dma_regs[a - 0x4300]   // regs 0x4300-0x437f
3737
38// add-on chip emulators
39#include "machine/snesobc1.c"
40#include "machine/snescx4.c"
41#include "machine/snesrtc.c"
42#include "machine/snessdd1.c"
43#include "machine/snes7110.c"
4438
45
4639VIDEO_START( snes )
4740{
4841   snes_state *state = machine.driver_data<snes_state>();
trunk/src/mame/mame.mak
r21589r21590
23802380
23812381$(DRIVERS)/galaxian.o:  $(MAMESRC)/drivers/galdrvr.c
23822382$(DRIVERS)/neogeo.o:    $(MAMESRC)/drivers/neodrvr.c
2383$(MACHINE)/snes.o:      $(MAMESRC)/machine/snesobc1.c \
2384         $(MAMESRC)/machine/snescx4.c \
2385         $(MAMESRC)/machine/cx4ops.c \
2386         $(MAMESRC)/machine/cx4oam.c \
2387         $(MAMESRC)/machine/cx4fn.c \
2388         $(MAMESRC)/machine/cx4data.c \
2389         $(MAMESRC)/machine/snesrtc.c \
2390         $(MAMESRC)/machine/snessdd1.c \
2391         $(MAMESRC)/machine/snes7110.c
23922383$(MACHINE)/nes_mmc.o:   $(MAMESRC)/machine/nes_ines.c \
23932384         $(MAMESRC)/machine/nes_pcb.c \
23942385         $(MAMESRC)/machine/nes_unif.c
trunk/src/mame/includes/snes.h
r21589r21590
766766
767767extern UINT8  *snes_ram;            /* Main memory */
768768
769// add-on chips IO
770void srtc_write(running_machine &machine, UINT16 addr, UINT8 data);
771UINT8 srtc_read(address_space &space, UINT16 addr);
772void srtc_init(running_machine &machine);
773extern DECLARE_READ8_HANDLER(obc1_read);
774extern DECLARE_WRITE8_HANDLER(obc1_write);
775void obc1_init(running_machine &machine);
776UINT8 CX4_read(UINT32 addr);
777void CX4_write(running_machine &machine, UINT32 addr, UINT8 data);
778UINT8 sdd1_mmio_read(address_space &space, UINT32 addr);
779void sdd1_mmio_write(address_space &space, UINT32 addr, UINT8 data);
780void sdd1_init(running_machine& machine);
781UINT8 sdd1_read(running_machine& machine, UINT32 addr);
782UINT8 spc7110_mmio_read(address_space &space, UINT32 addr);
783void spc7110_mmio_write(running_machine &machine, UINT32 addr, UINT8 data);
784UINT8 spc7110_bank7_read(address_space &space, UINT32 offset);
785void spc7110_init(running_machine& machine);
786void spc7110rtc_init(running_machine& machine);
787
788769extern struct snes_cart_info snes_cart;
789770
790771/*----------- defined in video/snes.c -----------*/

Previous 199869 Revisions Next


© 1997-2024 The MAME Team