Top secrets sources NedoPC pentevo

Rev

Rev 877 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed | ?url?

#include "std.h"

#include "emul.h"
#include "vars.h"
#include "gs.h"
#include "gsz80.h"
#include "vs1001.h"
#include "sdcard.h"
#include "debug.h"

#include "z80/op_noprefix.h"

#ifdef MOD_GSZ80
namespace z80gs
{
unsigned __int64 gs_t_states; // inc'ed with GSCPUINT every gs int
static unsigned __int64 gscpu_t_at_frame_start; // gs_t_states+gscpu.t when spectrum frame begins

Z80INLINE unsigned char rm(unsigned addr);
u8 __fastcall dbgrm(u32 addr);
Z80INLINE void wm(unsigned addr, unsigned char val);
void __fastcall dbgwm(u32 addr, u8 val);
Z80INLINE u8 *am_r(u32 addr);
Z80INLINE unsigned char m1_cycle(Z80 *cpu);
unsigned char in(unsigned port);
void out(unsigned port, unsigned char val);
// FIXME: Ñäåëàòü ïåðåêëþ÷àåìûé èíòåðôåéñ â çàâèñèìîñòè îò ôëàãà gscpu.dbgchk
namespace z80fast
{
Z80INLINE unsigned char xm(unsigned addr);
Z80INLINE unsigned char rm(unsigned addr);
Z80INLINE void wm(unsigned addr, unsigned char val);
}

namespace z80dbg
{
Z80INLINE unsigned char xm(unsigned addr);
Z80INLINE unsigned char rm(unsigned addr);
Z80INLINE void wm(unsigned addr, unsigned char val);
}

u8 __fastcall Xm(u32 addr)
{
    return z80gs::z80fast::xm(addr);
}

u8 __fastcall Rm(u32 addr)
{
    return z80gs::z80fast::rm(addr);
}

void __fastcall Wm(u32 addr, u8 val)
{
    z80gs::z80fast::wm(addr, val);
}

u8 __fastcall DbgXm(u32 addr)
{
    return z80gs::z80dbg::xm(addr);
}

u8 __fastcall DbgRm(u32 addr)
{
    return z80gs::z80dbg::rm(addr);
}

void __fastcall DbgWm(u32 addr, u8 val)
{
    z80gs::z80dbg::wm(addr, val);
}
}

u8 *TGsZ80::DirectMem(unsigned addr) const
{
    return z80gs::am_r(addr);
}

unsigned char TGsZ80::m1_cycle()
{
    return z80gs::m1_cycle(this);
}

unsigned char TGsZ80::in(unsigned port)
{
    return z80gs::in(port);
}

void TGsZ80::out(unsigned port, unsigned char val)
{
    z80gs::out(port, val);
}

void TGsZ80::retn()
{
    nmi_in_progress = false;
}

namespace z80gs
{
#include "z80/op_system.h"

const u8 MPAG   = 0x00;
const u8 MPAGEX = 0x10;

// gs
const u8 VOL1 = 0x06;
const u8 VOL2 = 0x07;
const u8 VOL3 = 0x08;
const u8 VOL4 = 0x09;

// nsg
const u8 VOL5 = 0x16;
const u8 VOL6 = 0x17;
const u8 VOL7 = 0x18;
const u8 VOL8 = 0x19;

const u8 DMA_MOD= 0x1b;
const u8 DMA_HAD= 0x1c;
const u8 DMA_MAD= 0x1d;
const u8 DMA_LAD= 0x1e;
const u8 DMA_CST= 0x1f;

const u8 GSCFG0 = 0x0F;

const u8 M_NOROM = 1;
const u8 M_RAMRO = 2;
const u8 M_EXPAG = 8;

const u8 M_8CHANS = 0x04;
const u8 M_PAN4CH = 0x40;

static u8 *gsbankr[4] = { ROM_GS_M, GSRAM_M + 3 * PAGE, ROM_GS_M, ROM_GS_M + PAGE }; // bank pointers for read
static u8 *gsbankw[4] = { TRASH_M, GSRAM_M + 3 * PAGE, TRASH_M, TRASH_M }; // bank pointers for write

static unsigned gs_v[8];
static unsigned char gsvol[8], gsbyte[8]{ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 };
static unsigned char gsdata_in, gsdata_out, gspage = 0;
static unsigned char gscmd, gsstat;

static bool GsSilent = false; // Ïðèçíàê íóëåâîé ãðîìêîñòè âî âñåõ êàíàëàõ

static unsigned long long mult_gs, mult_gs2;

// ngs
static u8 ngs_mode_pg1; // page ex number
static u8 ngs_cfg0;
static u8 ngs_s_ctrl;
static u8 ngs_s_stat;
static u8 SdRdVal, SdRdValNew;
static u8 ngs_dmamod;

static u8 ngs_chn_mask = 3;
static int vol_div = 256;

static bool SdDataAvail = false;

const unsigned GSINTFQ = 37500; // hz
static unsigned GSCPUFQI;
const unsigned GSCPUINT = GSCPUFQ/GSINTFQ;
const int MULT_GS_SHIFT = 12; // cpu tick -> gscpu tick precision
void flush_gs_z80();
void reset();
void nmi();

void apply_gs()
{
   GSCPUFQI = GSCPUFQ / conf.intfq;
   mult_gs = (temp.snd_frame_ticks << MULT_C)/GSCPUFQI;
   mult_gs2 = (GSCPUFQI<<MULT_GS_SHIFT)/conf.frame;

   make_gs_volume();
}

static inline void flush_gs_sound()
{
   if (temp.sndblock)
       return;

  unsigned l,r;         //!psb
  l = gs_v[0] + gs_v[1];    //!psb
  r = gs_v[2] + gs_v[3];    //!psb

  // ngs 8ch
  if(ngs_cfg0 & M_8CHANS)
  {
      l += gs_v[4] + gs_v[5];
      r += gs_v[6] + gs_v[7];
  }

   unsigned lv, rv;
   lv = (l + r/2) / 2;
   rv = (r + l/2) / 2;

/*
   if(gs_t_states < gscpu_t_at_frame_start)
   {
       printf("err: gs_t_states = %lld, gscpu_t_at_frame_start=%lld, gscpu.t = %u, t = %lld\n",
           gs_t_states, gscpu_t_at_frame_start, gscpu.t, ((gs_t_states + gscpu.t)  - gscpu_t_at_frame_start));
       fflush(stdout);
   }
*/


//   assert(gs_t_states >= gscpu_t_at_frame_start);

   sound.update(unsigned((gs_t_states + gscpu.t) - gscpu_t_at_frame_start), lv, rv);     //!psb
}

void init_gs_frame()
{
//   printf("%s, gs_t_states = %lld, gscpu.t = %u\n", __FUNCTION__, gs_t_states, gscpu.t);
   assert(gscpu.t < LONG_MAX);
   gscpu_t_at_frame_start = gs_t_states + gscpu.t;
   sound.start_frame();
}

void flush_gs_frame()
{
   flush_gs_z80();

/*   printf("%s, gs_t_states = %lld, gscpu_t_at_frame_start = %lld, gscpu.t = %u, t = %lld\n",
       __FUNCTION__, gs_t_states, gscpu_t_at_frame_start, gscpu.t,
       ((gs_t_states + gscpu.t)  - gscpu_t_at_frame_start));
*/

   sound.end_frame(unsigned((gs_t_states + gscpu.t) - gscpu_t_at_frame_start));

   for(int ch = 0; ch < 8; ch++)
   {
       gsleds[ch].level = abs(int(gsbyte[ch] - 0x80) * gsvol[ch]) / ((128 * 63) / 15);
       gsleds[ch].attrib = 0x0F;
   }
}

void out_gs(unsigned port, u8 val)
{
   port &= 0xFF;

   switch(port)
   {
   case 0x33: // GSCTR
       if(val & 0x80) // reset
       {
           reset();
           flush_gs_z80();
           return;
       }
       if(val & 0x40) // nmi
       {
           nmi();
           flush_gs_z80();
           return;
       }
       return;
   }

   flush_gs_z80();
   switch(port)
   {
   case 0xB3: // GSDAT
        gsdata_out = val;
        gsstat |= 0x80;
   break;
   case 0xBB: // GSCOM
       gscmd = val;
       gsstat |= 0x01;
   break;
   }
}

u8 in_gs(unsigned port)
{
   flush_gs_z80();
   port &= 0xFF;
   switch(port)
   {
   case 0xB3: gsstat &= 0x7F; return gsdata_in;
   case 0xBB: return gsstat | 0x7E;
   }
   return 0xFF;
}

static void gs_byte_to_dac(unsigned addr, unsigned char byte)
{
    if(GsSilent)
    {
        return;
    }

   flush_gs_sound();
   unsigned chan = (addr>>8) & ngs_chn_mask;
   gsbyte[chan] = byte;
//   gs_v[chan] = (gsbyte[chan] * gs_vfx[gsvol[chan]]) >> 8;
   gs_v[chan] = unsigned(((signed char)(gsbyte[chan]-0x80) * (signed)gs_vfx[gsvol[chan]]) / vol_div + int(gs_vfx[33])); //!psb
}

static inline void stepi();

Z80INLINE u8 *am_r(u32 addr)
{
   return &gsbankr[(addr >> 14U) & 3][addr & (PAGE-1)];
}

namespace z80fast
{
   #include "gsz80.inl"
}
namespace z80dbg
{
   #define Z80_DBG
   #include "gsz80.inl"
   #undef Z80_DBG
}

u8 *__fastcall MemDbg(u32 addr);

u8 *__fastcall MemDbg(u32 addr)
{
    return am_r(addr);
}

u8 __fastcall dbgrm(u32 addr)
{
    return z80dbg::rm(addr);
}

void __fastcall dbgwm(u32 addr, u8 val)
{
    *am_r(addr) = val;
}

void __cdecl BankNames(int i, char *Name)
{
    if(gsbankr[i] < GSRAM_M + MAX_GSRAM_PAGES*PAGE)
        sprintf(Name, "RAM%2lX", ULONG((gsbankr[i] - GSRAM_M) / PAGE));
    if((gsbankr[i] - ROM_GS_M) < PAGE*MAX_GSROM_PAGES)
        sprintf(Name, "ROM%2lX", ULONG((gsbankr[i] - ROM_GS_M) / PAGE));
}


Z80INLINE unsigned char m1_cycle(Z80 *cpu)
{
   cpu->r_low++; cpu->t += 4;
   return cpu->MemIf->xm(cpu->pc++);
}

static inline void UpdateMemMapping()
{
    bool RamRo = (ngs_cfg0 & M_RAMRO) != 0;
    bool NoRom = (ngs_cfg0 & M_NOROM) != 0;
    if(NoRom)
    {
        gsbankr[0] = gsbankw[0] = GSRAM_M;
        gsbankr[1] = gsbankw[1] = GSRAM_M + 3 * PAGE;
        gsbankr[2] = gsbankw[2] = GSRAM_M + gspage * PAGE;
        gsbankr[3] = gsbankw[3] = GSRAM_M + ngs_mode_pg1 * PAGE;

        if(RamRo)
        {
            if(gspage == 0 || gspage == 1) // RAM0 or RAM1 in PG2
               gsbankw[2] = TRASH_M;
            if(ngs_mode_pg1 == 0 || ngs_mode_pg1 == 1) // RAM0 or RAM1 in PG3
               gsbankw[3] = TRASH_M;
        }
    }
    else
    {
        gsbankw[0] = gsbankw[2] = gsbankw[3] = TRASH_M;
        gsbankr[0] = ROM_GS_M;                                  // ROM0
        gsbankr[1] = gsbankw[1] = GSRAM_M + 3 * PAGE;           // RAM3
        gsbankr[2] = ROM_GS_M +  (gspage & 0x1F) * PAGE;        // ROMn
        gsbankr[3] = ROM_GS_M +  (ngs_mode_pg1 & 0x1F) * PAGE;  // ROMm
    }
}

void out(unsigned port, unsigned char val)
{
//   printf(__FUNCTION__" port=0x%X, val=0x%X\n", (port & 0xFF), val);
   switch (port & 0xFF)
   {
      case MPAG:
      {
         bool ExtMem = (ngs_cfg0 & M_EXPAG) != 0;

         gspage = rol8(val, 1) & temp.gs_ram_mask & (ExtMem ? 0xFF : 0xFE);

         if(!ExtMem)
             ngs_mode_pg1 = (rol8(val, 1) & temp.gs_ram_mask) | 1;
//         printf(__FUNCTION__"->GSPG, %X, Ro=%d, NoRom=%d, Ext=%d\n", gspage, RamRo, NoRom, ExtMem);
         UpdateMemMapping();
         return;
      }
      case 0x02: gsstat &= 0x7F; return;
      case 0x03: gsstat |= 0x80; gsdata_in = val; return;
      case 0x05: gsstat &= 0xFE; return;

      case VOL1: case VOL2: case VOL3: case VOL4:
      case VOL5: case VOL6: case VOL7: case VOL8:
      {
         if((port & 0x10) && !(ngs_cfg0 & (M_8CHANS | M_PAN4CH)))
         {
             return;
         }

         val &= 0x3F;

         if(GsSilent && val == 0)
         {
             return;
         }

         flush_gs_sound();
         unsigned chan = ((port & 0x10) >> 2U) + (port & 0x0F)-6;
         gsvol[chan] = val;

         auto Chans = (ngs_cfg0 & M_8CHANS) ? 8 : 4;

         auto Silent = true;
         for(auto Ch = 0; Ch < Chans; Ch++)
         {
             if(gsvol[Ch] != 0)
             {
                 Silent = false;
                 break;
             }
         }

         GsSilent = Silent;

//         gs_v[chan] = (gsbyte[chan] * gs_vfx[gsvol[chan]]) >> 8;
         gs_v[chan] = unsigned(((signed char)(gsbyte[chan]-0x80) * (signed)gs_vfx[gsvol[chan]]) /vol_div + int(gs_vfx[33])); //!psb
         return;
      }
      case 0x0A: gsstat = u8((gsstat & 0x7F) | (gspage << 7)); return;
      case 0x0B: gsstat = u8((gsstat & 0xFE) | ((gsvol[0] >> 5) & 1)); return;

   }

//   printf(__FUNCTION__" port=0x%X, val=0x%X\n", (port & 0xFF), val);
   // ngs
   switch (port & 0xFF)
   {
      case GSCFG0:
      {
          ngs_cfg0 = val & 0x3F;
//          printf(__FUNCTION__"->GSCFG0, %X, Ro=%d, NoRom=%d, Ext=%d\n", ngs_cfg0, RamRo, NoRom, ExtMem);

          if(ngs_cfg0 & M_8CHANS)
          {
              ngs_chn_mask = 0x7;
              vol_div = 512;
          }
          else
          {
              ngs_chn_mask = 0x3;
              vol_div = 256;
          }
          UpdateMemMapping();
      }
      break;

      case MPAGEX:
      {
//          assert((ngs_cfg0 & M_EXPAG) != 0);
          ngs_mode_pg1 = rol8(val, 1) & temp.gs_ram_mask;
          UpdateMemMapping();
      }
      break;

      case S_CTRL:
//          printf(__FUNCTION__"->S_CTRL\n");
          if(val & 0x80)
              ngs_s_ctrl |= (val & 0xF);
          else
              ngs_s_ctrl &= ~(val & 0xF);

          if(!(ngs_s_ctrl & _MPXRS))
              Vs1001.Reset();

          Vs1001.SetNcs((ngs_s_ctrl & _MPNCS) != false);
      break;

      case MC_SEND:
          Vs1001.WrCmd(val);
      break;

      case MD_SEND:
          Vs1001.Wr(val);
      break;

      case SD_SEND:
          SdCard.Wr(val);
          SdRdValNew = SdCard.Rd();
          SdDataAvail = true;
      break;

      case DMA_MOD:
          ngs_dmamod = val;
      break;

      case DMA_HAD:
          if (ngs_dmamod == 1)
              temp.gsdmaaddr = (temp.gsdmaaddr&0x0000ffff)|(unsigned(val & 0x1F)<<16); // 5bit only
      break;

      case DMA_MAD:
          if (ngs_dmamod == 1)
              temp.gsdmaaddr = (temp.gsdmaaddr&0x001f00ff)|(unsigned(val)<<8);
      break;

      case DMA_LAD:
          if (ngs_dmamod == 1)
              temp.gsdmaaddr = (temp.gsdmaaddr&0x001fff00)|val;
      break;

      case DMA_CST:
          if (ngs_dmamod == 1)
              temp.gsdmaon = val;
      break;
   }
}

unsigned char in(unsigned port)
{
   switch (port & 0xFF)
   {
      case 0x01: return gscmd;
      case 0x02: gsstat &= 0x7F; return gsdata_out;
      case 0x03: gsstat |= 0x80; gsdata_in = 0xFF; return 0xFF;
      case 0x04: return gsstat;
      case 0x05: gsstat &= 0xFE; return 0xFF;
      case 0x0A: gsstat = u8((gsstat & 0x7F) | (gspage << 7)); return 0xFF;
      case 0x0B: gsstat = u8((gsstat & 0xFE) | (gsvol[0] >> 5)); return 0xFF;


      // ngs
      case GSCFG0:
          return ngs_cfg0;
      case S_CTRL:
          return ngs_s_ctrl;

      case S_STAT:
          if(Vs1001.GetDreq())
              ngs_s_stat |= _MPDRQ;
          else
              ngs_s_stat &= ~_MPDRQ;
          return ngs_s_stat;

      case MC_READ:
          return Vs1001.Rd();

      case SD_READ:
      {
          u8 Tmp = SdRdVal;
          SdRdVal = SdRdValNew;
          return Tmp;
      }
      case SD_RSTR:
          if(SdDataAvail)
          {
              SdDataAvail = false;
              return SdRdValNew;
          }
          return SdCard.Rd();

      case DMA_MOD:
          return ngs_dmamod;

      case DMA_HAD:
          if (ngs_dmamod == 1)
              return (temp.gsdmaaddr>>16) & 0x1F; // 5bit only
      break;

      case DMA_MAD:
          if (ngs_dmamod == 1)
              return (temp.gsdmaaddr>>8) & 0xFF;
      break;

      case DMA_LAD:
          if (ngs_dmamod == 1)
              return temp.gsdmaaddr & 0xFF;
      break;

      case DMA_CST:
          if (ngs_dmamod == 1)
              return temp.gsdmaon;
      break;
   }
   return 0xFF;
}

//#include "z80/cmd.cpp"

static inline void stepi()
{
   u8 opcode = m1_cycle(&gscpu);
   (::normal_opcode[opcode])(&gscpu);
}

void Z80FAST step();

void Z80FAST step()
{
    stepi();
}

void flush_gs_z80()
{
   if(gscpu.dbgchk)
   {
       gscpu.SetDbgMemIf();
       z80gs::z80dbg::z80loop();
   }
   else
   {
       gscpu.SetFastMemIf();
       z80gs::z80fast::z80loop();
   }
}

__int64 __cdecl delta()
{
    return i64(gs_t_states) + gscpu.t - gscpu.debug_last_t;
}

void __cdecl SetLastT()
{
   gscpu.debug_last_t = i64(gs_t_states + gscpu.t);
}

void nmi()
{
   gscpu.sp -= 2;
   z80fast::wm(gscpu.sp, gscpu.pcl);
   z80fast::wm(gscpu.sp+1, gscpu.pch);
   gscpu.pc = 0x66;
   gscpu.iff1 = gscpu.halted = 0;
}

void reset()
{
   gscpu.reset();
   gsbankr[0] = ROM_GS_M; gsbankr[1] = GSRAM_M + 3 * PAGE; gsbankr[2] = ROM_GS_M; gsbankr[3] = ROM_GS_M + PAGE;
   gsbankw[0] = TRASH_M; gsbankw[1] = GSRAM_M + 3 * PAGE; gsbankw[2] = TRASH_M; gsbankw[3] = TRASH_M;

   gscpu.t = 0;
   gs_t_states = 0;
   gscpu_t_at_frame_start = 0;
   ngs_cfg0 = 0;
   ngs_s_stat = u8(u8(rdtsc() & ~7U) | _SDDET | _MPDRQ);
   ngs_s_ctrl = u8(u8(rdtsc() & ~0xFU) | _SDNCS);
   SdRdVal = SdRdValNew = 0xFF;
   SdDataAvail = false;
   Vs1001.Reset();

   for(unsigned i = 0; i < 8; i++)
   {
       gsbyte[i] = 0x80;
       gsvol[i] = 0;
       gs_v[i] = 0;
   }

   ngs_mode_pg1 = 1;
   ngs_dmamod = 0;
   temp.gsdmaaddr = 0;
   temp.gsdmaon = 0;
   SdCard.Reset();
}

} // end of z80gs namespace
#endif