#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;
// эхъюЄюЁ√х юс· тыхэ√ т gsz80.h
const unsigned GSINTFQ = 37500; // Hz
static unsigned GSCPUFQI; // 489795 = 24000000 / 49
const unsigned GSCPUINT = GSCPUFQ/GSINTFQ; // 640 = 24000000 / 37500
const int MULT_GS_SHIFT = 12; // cpu tick -> gscpu tick precision
// яюўхьє 12 ????????
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 VOL1...VOL8:
//---------------------------------------------------------------------
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);
//printf ("GSINTFQ %d\n",GSINTFQ);
//printf ("GSCPUFQI %d\n",GSCPUFQI);
//printf ("GSCPUFQ %d\n",GSCPUFQ);
//printf ("GSCPUINT %d\n",GSCPUINT);
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
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 //#ifdef MOD_GSZ80
//=============================================================================