Previous 199869 Revisions Next

r17642 Tuesday 4th September, 2012 at 19:08:03 UTC by Angelo Salese
Moved multiplication and division operation from SNES to 5A22 CPU core file [Angelo Salese]
[src/emu/cpu/g65816]g65816.c g65816cm.h
[src/mame/includes]snes.h
[src/mame/machine]snes.c

trunk/src/mame/machine/snes.c
r17641r17642
291291   state->m_scanline_timer->adjust(machine.primary_screen->time_until_pos(nextscan));
292292}
293293
294/* FIXME: multiplication should take 8 CPU cycles & division 16 CPU cycles, but
295using these timers breaks e.g. Chrono Trigger intro and Super Tennis gameplay.
296On the other hand, timers are needed for the translation of Breath of Fire 2
297to work. More weirdness: we might need to leave 8 CPU cycles for division at
298first, since using 16 produces bugs (see e.g. Triforce pieces in Zelda 3 intro) */
299294
300static TIMER_CALLBACK(snes_div_callback)
301{
302   UINT16 value, dividend, remainder;
303   dividend = remainder = 0;
304   value = (snes_ram[WRDIVH] << 8) + snes_ram[WRDIVL];
305   if (snes_ram[WRDVDD] > 0)
306   {
307      dividend = value / snes_ram[WRDVDD];
308      remainder = value % snes_ram[WRDVDD];
309   }
310   else
311   {
312      dividend = 0xffff;
313      remainder = value;
314   }
315   snes_ram[RDDIVL] = dividend & 0xff;
316   snes_ram[RDDIVH] = (dividend >> 8) & 0xff;
317   snes_ram[RDMPYL] = remainder & 0xff;
318   snes_ram[RDMPYH] = (remainder >> 8) & 0xff;
319}
320
321
322static TIMER_CALLBACK(snes_mult_callback)
323{
324   UINT32 c = snes_ram[WRMPYA] * snes_ram[WRMPYB];
325   snes_ram[RDMPYL] = c & 0xff;
326   snes_ram[RDMPYH] = (c >> 8) & 0xff;
327}
328
329295/*************************************
330296
331297    Input Handlers
r17641r17642
555521         return (snes_ram[offset] & 0xc1) | (snes_open_bus_r(space, 0) & 0x3e);
556522      case RDIO:         /* Programmable I/O port - echos back what's written to WRIO */
557523         return snes_ram[WRIO];
558      case RDDIVL:      /* Quotient of divide result (low) */
559      case RDDIVH:      /* Quotient of divide result (high) */
560      case RDMPYL:      /* Product/Remainder of mult/div result (low) */
561      case RDMPYH:      /* Product/Remainder of mult/div result (high) */
562         return snes_ram[offset];
563524      case JOY1L:         /* Joypad 1 status register (low) */
564525         if(state->m_is_nss && state->m_input_disabled)
565526            return 0;
r17641r17642
740701            snes_latch_counters(space->machine());
741702         }
742703         break;
743      case WRMPYA:   /* Multiplier A */
744         break;
745      case WRMPYB:   /* Multiplier B */
746         snes_ram[WRMPYB] = data;
747//          state->m_mult_timer->adjust(state->m_maincpu->cycles_to_attotime(8));
748         {
749            UINT32 c = snes_ram[WRMPYA] * snes_ram[WRMPYB];
750            snes_ram[RDMPYL] = c & 0xff;
751            snes_ram[RDMPYH] = (c >> 8) & 0xff;
752         }
753         break;
754      case WRDIVL:   /* Dividend (low) */
755      case WRDIVH:   /* Dividend (high) */
756         break;
757      case WRDVDD:   /* Divisor */
758         snes_ram[WRDVDD] = data;
759//          state->m_div_timer->adjust(state->m_maincpu->cycles_to_attotime(16));
760         {
761            UINT16 value, dividend, remainder;
762            value = (snes_ram[WRDIVH] << 8) + snes_ram[WRDIVL];
763            if (snes_ram[WRDVDD] > 0)
764            {
765               dividend = value / data;
766               remainder = value % data;
767            }
768            else
769            {
770               dividend = 0xffff;
771               remainder = value;
772            }
773            snes_ram[RDDIVL] = dividend & 0xff;
774            snes_ram[RDDIVH] = (dividend >> 8) & 0xff;
775            snes_ram[RDMPYL] = remainder & 0xff;
776            snes_ram[RDMPYH] = (remainder >> 8) & 0xff;
777         }
778         break;
779704      case HTIMEL:   /* H-Count timer settings (low)  */
780705         state->m_htime = (state->m_htime & 0xff00) | (data <<  0);
781706         state->m_htime &= 0x1ff;
r17641r17642
813738      case MPYM:      /* Multiplication result (mid) */
814739      case MPYH:      /* Multiplication result (high) */
815740      case RDIO:
816      case RDDIVL:
817      case RDDIVH:
818      case RDMPYL:
819      case RDMPYH:
741//      case RDDIVL:
742//      case RDDIVH:
743//      case RDMPYL:
744//      case RDMPYH:
820745      case JOY1L:
821746      case JOY1H:
822747      case JOY2L:
r17641r17642
16201545   state->m_nmi_timer->adjust(attotime::never);
16211546   state->m_hirq_timer = machine.scheduler().timer_alloc(FUNC(snes_hirq_tick_callback));
16221547   state->m_hirq_timer->adjust(attotime::never);
1623   state->m_div_timer = machine.scheduler().timer_alloc(FUNC(snes_div_callback));
1624   state->m_div_timer->adjust(attotime::never);
1625   state->m_mult_timer = machine.scheduler().timer_alloc(FUNC(snes_mult_callback));
1626   state->m_mult_timer->adjust(attotime::never);
1548   //state->m_div_timer = machine.scheduler().timer_alloc(FUNC(snes_div_callback));
1549   //state->m_div_timer->adjust(attotime::never);
1550   //state->m_mult_timer = machine.scheduler().timer_alloc(FUNC(snes_mult_callback));
1551   //state->m_mult_timer->adjust(attotime::never);
16271552   state->m_io_timer = machine.scheduler().timer_alloc(FUNC(snes_update_io));
16281553   state->m_io_timer->adjust(attotime::never);
16291554
r17641r17642
17621687
17631688   // power-on sets these registers like this
17641689   snes_ram[WRIO] = 0xff;
1765   snes_ram[WRMPYA] = 0xff;
1766   snes_ram[WRDIVL] = 0xff;
1767   snes_ram[WRDIVH] = 0xff;
1690//   snes_ram[WRMPYA] = 0xff;
1691//   snes_ram[WRDIVL] = 0xff;
1692//   snes_ram[WRDIVH] = 0xff;
17681693
17691694   switch (state->m_has_addon_chip)
17701695   {
trunk/src/mame/includes/snes.h
r17641r17642
146146#define OLDJOY2        0x4017
147147#define NMITIMEN       0x4200
148148#define WRIO           0x4201
149#define WRMPYA         0x4202
150#define WRMPYB         0x4203
151#define WRDIVL         0x4204
152#define WRDIVH         0x4205
153#define WRDVDD         0x4206
149//#define WRMPYA         0x4202
150//#define WRMPYB         0x4203
151//#define WRDIVL         0x4204
152//#define WRDIVH         0x4205
153//#define WRDVDD         0x4206
154154#define HTIMEL         0x4207
155155#define HTIMEH         0x4208
156156#define VTIMEL         0x4209
r17641r17642
162162#define TIMEUP         0x4211
163163#define HVBJOY         0x4212
164164#define RDIO           0x4213
165#define RDDIVL         0x4214
166#define RDDIVH         0x4215
167#define RDMPYL         0x4216
168#define RDMPYH         0x4217
165//#define RDDIVL         0x4214
166//#define RDDIVH         0x4215
167//#define RDMPYL         0x4216
168//#define RDMPYH         0x4217
169169#define JOY1L          0x4218
170170#define JOY1H          0x4219
171171#define JOY2L          0x421A
r17641r17642
439439   emu_timer             *m_hblank_timer;
440440   emu_timer             *m_nmi_timer;
441441   emu_timer             *m_hirq_timer;
442   emu_timer             *m_div_timer;
443   emu_timer             *m_mult_timer;
442//   emu_timer             *m_div_timer;
443//   emu_timer             *m_mult_timer;
444444   emu_timer             *m_io_timer;
445445
446446   /* DMA/HDMA-related */
trunk/src/emu/cpu/g65816/g65816.c
r17641r17642
571571   CPU_RESET_CALL(g65816);
572572
573573   cpustate->fastROM = 0;
574   cpustate->wrmpya = 0xff;
575   cpustate->wrdiv = 0xffff;
574576}
575577
578/* TODO: multiplication / division should actually occur inside CPU_EXECUTE */
579/* (Old note, for reference): multiplication should take 8 CPU cycles &
580division 16 CPU cycles, but using these timers breaks e.g. Chrono Trigger
581intro and Super Tennis gameplay. On the other hand, timers are needed for the
582translation of Breath of Fire 2 to work. More weirdness: we might need to leave
5838 CPU cycles for division at first, since using 16 produces bugs (see e.g.
584Triforce pieces in Zelda 3 intro) */
585
586static WRITE8_HANDLER( wrmpya_w )
587{
588   g65816i_cpu_struct *cpustate = get_safe_token(&space->device());
589
590   cpustate->wrmpya = data;
591}
592
593static WRITE8_HANDLER( wrmpyb_w )
594{
595   g65816i_cpu_struct *cpustate = get_safe_token(&space->device());
596
597   cpustate->wrmpyb = data;
598   cpustate->rdmpy = cpustate->wrmpya * cpustate->wrmpyb;
599   /* TODO: cpustate->rddiv == 0? */
600}
601
602static WRITE8_HANDLER( wrdivl_w )
603{
604   g65816i_cpu_struct *cpustate = get_safe_token(&space->device());
605
606   cpustate->wrdiv = (data) | (cpustate->wrdiv & 0xff00);
607}
608
609static WRITE8_HANDLER( wrdivh_w )
610{
611   g65816i_cpu_struct *cpustate = get_safe_token(&space->device());
612
613   cpustate->wrdiv = (data << 8) | (cpustate->wrdiv & 0xff);
614}
615
616static WRITE8_HANDLER( wrdvdd_w )
617{
618   g65816i_cpu_struct *cpustate = get_safe_token(&space->device());
619   UINT16 quotient, remainder;
620
621   cpustate->dvdd = data;
622
623   if(cpustate->dvdd != 0)
624   {
625      quotient = cpustate->wrdiv / cpustate->dvdd;
626      remainder = cpustate->wrdiv % cpustate->dvdd;
627   }
628   else
629   {
630      quotient = 0xffff;
631      remainder = 0x000c;
632   }
633
634   cpustate->rddiv = quotient;
635   cpustate->rdmpy = remainder;
636}
637
638static READ8_HANDLER( rddivl_r )
639{
640   g65816i_cpu_struct *cpustate = get_safe_token(&space->device());
641   return cpustate->rddiv & 0xff;
642}
643
644static READ8_HANDLER( rddivh_r )
645{
646   g65816i_cpu_struct *cpustate = get_safe_token(&space->device());
647   return cpustate->rddiv >> 8;
648}
649
650static READ8_HANDLER( rdmpyl_r )
651{
652   g65816i_cpu_struct *cpustate = get_safe_token(&space->device());
653   return cpustate->rdmpy & 0xff;
654}
655
656static READ8_HANDLER( rdmpyh_r )
657{
658   g65816i_cpu_struct *cpustate = get_safe_token(&space->device());
659   return cpustate->rdmpy >> 8;
660}
661
662
663static ADDRESS_MAP_START(_5a22_map, AS_PROGRAM, 8, legacy_cpu_device)
664   AM_RANGE(0x4202, 0x4202) AM_MIRROR(0x3f0000) AM_WRITE_LEGACY(wrmpya_w)
665   AM_RANGE(0x4203, 0x4203) AM_MIRROR(0x3f0000) AM_WRITE_LEGACY(wrmpyb_w)
666   AM_RANGE(0x4204, 0x4204) AM_MIRROR(0x3f0000) AM_WRITE_LEGACY(wrdivl_w)
667   AM_RANGE(0x4205, 0x4205) AM_MIRROR(0x3f0000) AM_WRITE_LEGACY(wrdivh_w)
668   AM_RANGE(0x4206, 0x4206) AM_MIRROR(0x3f0000) AM_WRITE_LEGACY(wrdvdd_w)
669
670   AM_RANGE(0x4214, 0x4214) AM_MIRROR(0x3f0000) AM_READ_LEGACY(rddivl_r)
671   AM_RANGE(0x4215, 0x4215) AM_MIRROR(0x3f0000) AM_READ_LEGACY(rddivh_r)
672   AM_RANGE(0x4216, 0x4216) AM_MIRROR(0x3f0000) AM_READ_LEGACY(rdmpyl_r)
673   AM_RANGE(0x4217, 0x4217) AM_MIRROR(0x3f0000) AM_READ_LEGACY(rdmpyh_r)
674
675ADDRESS_MAP_END
676
576677CPU_SET_INFO( _5a22 )
577678{
578679   g65816i_cpu_struct *cpustate = (device != NULL && device->token() != NULL) ? get_safe_token(device) : NULL;
r17641r17642
600701      case CPUINFO_STR_NAME:                     strcpy(info->s, "5A22");         break;
601702      case CPUINFO_INT_REGISTER + _5A22_FASTROM:      info->i = g65816_get_reg(cpustate, _5A22_FASTROM); break;
602703      case CPUINFO_STR_REGISTER + _5A22_FASTROM:      sprintf(info->s, "fastROM:%d", cpustate->fastROM & 1 ? 1 : 0); break;
704      case CPUINFO_PTR_INTERNAL_MEMORY_MAP + AS_PROGRAM:   info->internal_map8 = ADDRESS_MAP_NAME(_5a22_map); break;
603705
604706      default:                              CPU_GET_INFO_CALL(g65816);            break;
605707   }
trunk/src/emu/cpu/g65816/g65816cm.h
r17641r17642
110110   int ICount;
111111   int cpu_type;
112112   UINT8 rw8_cycles, rw16_cycles, rw24_cycles;
113
114   /* 5A22 specific registers */
115   UINT8 wrmpya, wrmpyb;
116   UINT16 rdmpy;
117   UINT16 wrdiv;
118   UINT8 dvdd;
119   UINT16 rddiv;
113120};
114121
115122extern void (*const *const g65816i_opcodes[])(g65816i_cpu_struct *cpustate);

Previous 199869 Revisions Next


© 1997-2024 The MAME Team