void SPC7110::mmio_write()

in cores/snes/spc7110emu.cpp [348:642]


void SPC7110::mmio_write(unsigned addr, uint8 data) {
  addr &= 0xffff;

  switch(addr) {
    //==================
    //decompression unit
    //==================

    case 0x4801: r4801 = data; break;
    case 0x4802: r4802 = data; break;
    case 0x4803: r4803 = data; break;
    case 0x4804: r4804 = data; break;
    case 0x4805: r4805 = data; break;
    case 0x4806: {
      r4806 = data;

      unsigned table   = (r4801 + (r4802 << 8) + (r4803 << 16));
      unsigned index   = (r4804 << 2);
      //unsigned length  = (r4809 + (r480a << 8));
      unsigned addr    = datarom_addr(table + index);
      unsigned mode    = (memory_cartrom_read(addr + 0));
      unsigned offset  = (memory_cartrom_read(addr + 1) << 16)
                       + (memory_cartrom_read(addr + 2) <<  8)
                       + (memory_cartrom_read(addr + 3) <<  0);

      decomp.init(mode, offset, (r4805 + (r4806 << 8)) << mode);
      r480c = 0x80;
    } break;

    case 0x4807: r4807 = data; break;
    case 0x4808: r4808 = data; break;
    case 0x4809: r4809 = data; break;
    case 0x480a: r480a = data; break;
    case 0x480b: r480b = data; break;

    //==============
    //data port unit
    //==============

    case 0x4811: r4811 = data; r481x |= 0x01; break;
    case 0x4812: r4812 = data; r481x |= 0x02; break;
    case 0x4813: r4813 = data; r481x |= 0x04; break;
    case 0x4814: {
      r4814 = data;
      r4814_latch = true;
      if(!r4815_latch) break;
      if(!(r4818 & 2)) break;
      if(r4818 & 0x10) break;

      if((r4818 & 0x60) == 0x20) {
        unsigned increment = data_adjust() & 0xff;
        if(r4818 & 8) increment = (int8)increment;  //8-bit sign extend
        set_data_pointer(data_pointer() + increment);
      } else if((r4818 & 0x60) == 0x40) {
        unsigned increment = data_adjust();
        if(r4818 & 8) increment = (int16)increment;  //16-bit sign extend
        set_data_pointer(data_pointer() + increment);
      }
    } break;
    case 0x4815: {
      r4815 = data;
      r4815_latch = true;
      if(!r4814_latch) break;
      if(!(r4818 & 2)) break;
      if(r4818 & 0x10) break;

      if((r4818 & 0x60) == 0x20) {
        unsigned increment = data_adjust() & 0xff;
        if(r4818 & 8) increment = (int8)increment;  //8-bit sign extend
        set_data_pointer(data_pointer() + increment);
      } else if((r4818 & 0x60) == 0x40) {
        unsigned increment = data_adjust();
        if(r4818 & 8) increment = (int16)increment;  //16-bit sign extend
        set_data_pointer(data_pointer() + increment);
      }
    } break;
    case 0x4816: r4816 = data; break;
    case 0x4817: r4817 = data; break;
    case 0x4818: {
      if(r481x != 0x07) break;

      r4818 = data;
      r4814_latch = r4815_latch = false;
    } break;

    //=========
    //math unit
    //=========

    case 0x4820: r4820 = data; break;
    case 0x4821: r4821 = data; break;
    case 0x4822: r4822 = data; break;
    case 0x4823: r4823 = data; break;
    case 0x4824: r4824 = data; break;
    case 0x4825: {
      r4825 = data;

      if(r482e & 1) {
        //signed 16-bit x 16-bit multiplication
        int16 r0 = (int16)(r4824 + (r4825 << 8));
        int16 r1 = (int16)(r4820 + (r4821 << 8));

        signed result = r0 * r1;
        r4828 = result;
        r4829 = result >> 8;
        r482a = result >> 16;
        r482b = result >> 24;
      } else {
        //unsigned 16-bit x 16-bit multiplication
        uint16 r0 = (uint16)(r4824 + (r4825 << 8));
        uint16 r1 = (uint16)(r4820 + (r4821 << 8));

        unsigned result = r0 * r1;
        r4828 = result;
        r4829 = result >> 8;
        r482a = result >> 16;
        r482b = result >> 24;
      }

      r482f = 0x80;
    } break;
    case 0x4826: r4826 = data; break;
    case 0x4827: {
      r4827 = data;

      if(r482e & 1) {
        //signed 32-bit x 16-bit division
        int32 dividend = (int32)(r4820 + (r4821 << 8) + (r4822 << 16) + (r4823 << 24));
        int16 divisor  = (int16)(r4826 + (r4827 << 8));

        int32 quotient;
        int16 remainder;

        if(divisor) {
          quotient  = (int32)(dividend / divisor);
          remainder = (int32)(dividend % divisor);
        } else {
          //illegal division by zero
          quotient  = 0;
          remainder = dividend & 0xffff;
        }

        r4828 = quotient;
        r4829 = quotient >> 8;
        r482a = quotient >> 16;
        r482b = quotient >> 24;

        r482c = remainder;
        r482d = remainder >> 8;
      } else {
        //unsigned 32-bit x 16-bit division
        uint32 dividend = (uint32)(r4820 + (r4821 << 8) + (r4822 << 16) + (r4823 << 24));
        uint16 divisor  = (uint16)(r4826 + (r4827 << 8));

        uint32 quotient;
        uint16 remainder;

        if(divisor) {
          quotient  = (uint32)(dividend / divisor);
          remainder = (uint16)(dividend % divisor);
        } else {
          //illegal division by zero
          quotient  = 0;
          remainder = dividend & 0xffff;
        }

        r4828 = quotient;
        r4829 = quotient >> 8;
        r482a = quotient >> 16;
        r482b = quotient >> 24;

        r482c = remainder;
        r482d = remainder >> 8;
      }

      r482f = 0x80;
    } break;

    case 0x482e: {
      //reset math unit
      r4820 = r4821 = r4822 = r4823 = 0;
      r4824 = r4825 = r4826 = r4827 = 0;
      r4828 = r4829 = r482a = r482b = 0;
      r482c = r482d = 0;

      r482e = data;
    } break;

    //===================
    //memory mapping unit
    //===================

    case 0x4830: r4830 = data; break;

    case 0x4831: {
      r4831 = data;
      dx_offset = datarom_addr((data & 7) * 0x100000);
    } break;

    case 0x4832: {
      r4832 = data;
      ex_offset = datarom_addr((data & 7) * 0x100000);
    } break;

    case 0x4833: {
      r4833 = data;
      fx_offset = datarom_addr((data & 7) * 0x100000);
    } break;

    case 0x4834: r4834 = data; break;

    //====================
    //real-time clock unit
    //====================

    case 0x4840: {
      r4840 = data;
      if(!(r4840 & 1)) {
        //disable RTC
        rtc_state = RTCS_Inactive;
        update_time();
      } else {
        //enable RTC
        r4842 = 0x80;
        rtc_state = RTCS_ModeSelect;
      }
    } break;

    case 0x4841: {
      r4841 = data;

      switch(rtc_state) {
        case RTCS_ModeSelect: {
          if(data == RTCM_Linear || data == RTCM_Indexed) {
            r4842 = 0x80;
            rtc_state = RTCS_IndexSelect;
            rtc_mode  = (RTC_Mode)data;
            rtc_index = 0;
          }
        } break;

        case RTCS_IndexSelect: {
          r4842 = 0x80;
          rtc_index = data & 15;
          if(rtc_mode == RTCM_Linear) rtc_state = RTCS_Write;
        } break;

        case RTCS_Write: {
          r4842 = 0x80;

          //control register 0
          if(rtc_index == 13) {
            //increment second counter
            if(data & 2) update_time(+1);

            //round minute counter
            if(data & 8) {
              update_time();

              unsigned second = memory_cartrtc_read( 0) + memory_cartrtc_read( 1) * 10;
              //clear seconds
              memory_cartrtc_write(0, 0);
              memory_cartrtc_write(1, 0);

              if(second >= 30) update_time(+60);
            }
          }

          //control register 2
          if(rtc_index == 15) {
            //disable timer and clear second counter
            if((data & 1) && !(memory_cartrtc_read(15) & 1)) {
              update_time();

              //clear seconds
              memory_cartrtc_write(0, 0);
              memory_cartrtc_write(1, 0);
            }

            //disable timer
            if((data & 2) && !(memory_cartrtc_read(15) & 2)) {
              update_time();
            }
          }

          memory_cartrtc_write(rtc_index, data & 15);
          rtc_index = (rtc_index + 1) & 15;
        } break;

		case RTCS_Inactive: {
		} break;
      } //switch(rtc_state)
    } break;
  }
}