/* sigma_map.c: XDS Sigma memory access routines | |
Copyright (c) 2007-2017, Robert M Supnik | |
Permission is hereby granted, free of charge, to any person obtaining a | |
copy of this software and associated documentation files (the "Software"), | |
to deal in the Software without restriction, including without limitation | |
the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
and/or sell copies of the Software, and to permit persons to whom the | |
Software is furnished to do so, subject to the following conditions: | |
The above copyright notice and this permission notice shall be included in | |
all copies or substantial portions of the Software. | |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | |
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
Except as contained in this notice, the name of Robert M Supnik shall not be | |
used in advertising or otherwise to promote the sale, use or other dealings | |
in this Software without prior written authorization from Robert M Supnik. | |
13-Mar-17 RMS Annotated fall through in switch | |
*/ | |
#include "sigma_defs.h" | |
#define BVA_REG (RF_NUM << 2) | |
#define BPAMASK ((cpu_tab[cpu_model].pamask << 2) | 0x3) | |
#define NUM_MUNITS (MAXMEMSIZE / CPU_MUNIT_SIZE) | |
/* Sigma 8-9 memory status words */ | |
#define S89_SR0_BADLMS 0x00800000 /* bad LMS */ | |
#define S89_SR0_RD (S89_SR0_BADLMS) | |
#define S89_SR0_V_PORTS 12 | |
#define S89_SR1_FIXED 0x50C40000 /* always 1 */ | |
#define S89_SR1_M_MEMU 0xF /* mem unit */ | |
#define S89_SR1_V_MEMU 24 | |
#define S89_SR1_MARG 0x00F80000 /* margin write */ | |
#define S89_SR1_MAROFF 2 /* offset to read */ | |
/* 5X0 memory status words */ | |
#define S5X0_SR0_FIXED 0x40000000 | |
#define S5X0_SR0_BADLMS 0x00000004 /* bad LMS */ | |
#define S5X0_SR0_RD (S5X0_SR0_BADLMS) | |
#define S5X0_SR0_V_PORTS 21 | |
#define S5X0_SR1_FIXED 0xB0000000 /* fixed */ | |
#define S5X0_SR1_M_MEMU 0x7 /* mem unit */ | |
#define S5X0_SR1_V_MEMU 25 | |
#define S5X0_SR1_V_SA 18 /* start addr */ | |
#define S8 | |
typedef struct { | |
uint32 width; /* item width */ | |
uint32 dmask; /* data mask */ | |
uint32 cmask; /* control start mask */ | |
uint32 lnt; /* array length */ | |
uint32 opt; /* option control */ | |
} mmc_ctl_t; | |
uint16 mmc_rel[VA_NUM_PAG]; | |
uint8 mmc_acc[VA_NUM_PAG]; | |
uint8 mmc_wlk[PA_NUM_PAG]; | |
uint32 mem_sr0[NUM_MUNITS]; | |
uint32 mem_sr1[NUM_MUNITS]; | |
mmc_ctl_t mmc_tab[8] = { | |
{ 0, 0, 0, 0 }, | |
{ 2, 0x003, 0, MMC_L_CS1, CPUF_WLK }, /* map 1: 2b locks */ | |
{ 2, 0x003, MMC_M_CS2, MMC_L_CS2, CPUF_MAP }, /* map 2: 2b access ctls */ | |
{ 4, 0x00F, MMC_M_CS3, MMC_L_CS3, CPUF_WLK }, /* map 3: 4b locks */ | |
{ 8, 0x0FF, MMC_M_CS4, MMC_L_CS4, CPUF_MAP }, /* map 4: 8b relocation */ | |
{ 16, 0x7FF, MMC_M_CS5, MMC_L_CS5, CPUF_MAP }, /* map 5: 16b relocation */ | |
{ 0, 0, 0, 0 }, | |
{ 0, 0, 0, 0 } | |
}; | |
extern uint32 *R; | |
extern uint32 *M; | |
extern uint32 PSW1, PSW2, PSW4; | |
extern uint32 CC, PSW2_WLK; | |
extern uint32 stop_op; | |
extern uint32 cpu_model; | |
extern uint32 chan_num; | |
extern UNIT cpu_unit; | |
extern cpu_var_t cpu_tab[]; | |
uint32 map_reloc (uint32 bva, uint32 acc, uint32 *bpa); | |
uint32 map_viol (uint32 bva, uint32 bpa, uint32 tr); | |
t_stat map_reset (DEVICE *dptr); | |
uint32 map_las (uint32 rn, uint32 bva); | |
/* Map data structures | |
map_dev map device descriptor | |
map_unit map units | |
map_reg map register list | |
*/ | |
UNIT map_unit = { UDATA (NULL, 0, 0) }; | |
REG map_reg[] = { | |
{ BRDATA (REL, mmc_rel, 16, 13, VA_NUM_PAG) }, | |
{ BRDATA (ACC, mmc_acc, 16, 2, VA_NUM_PAG) }, | |
{ BRDATA (WLK, mmc_wlk, 16, 4, PA_NUM_PAG) }, | |
{ BRDATA (SR0, mem_sr0, 16, 32, NUM_MUNITS) }, | |
{ BRDATA (SR1, mem_sr1, 16, 32, NUM_MUNITS) }, | |
{ NULL } | |
}; | |
DEVICE map_dev = { | |
"MAP", &map_unit, map_reg, NULL, | |
1, 16, 16, 1, 16, 32, | |
NULL, NULL, &map_reset, | |
NULL, NULL, NULL, | |
NULL, 0 | |
}; | |
/* Read and write virtual routines - per length */ | |
uint32 ReadB (uint32 bva, uint32 *dat, uint32 acc) | |
{ | |
uint32 bpa, sc, tr; | |
sc = 24 - ((bva & 3) << 3); | |
if (bva < BVA_REG) /* register access */ | |
*dat = (R[bva >> 2] >> sc) & BMASK; | |
else { /* memory access */ | |
if ((tr = map_reloc (bva, acc, &bpa)) != 0) /* relocate addr */ | |
return tr; | |
*dat = (M[bpa >> 2] >> sc) & BMASK; | |
} /* end else memory */ | |
return 0; | |
} | |
uint32 ReadH (uint32 bva, uint32 *dat, uint32 acc) | |
{ | |
uint32 bpa, tr; | |
if (bva < BVA_REG) { /* register access */ | |
if (bva & 2) | |
*dat = R[bva >> 2] & HMASK; | |
else *dat = (R[bva >> 2] >> 16) & HMASK; | |
} | |
else { /* memory access */ | |
if ((tr = map_reloc (bva, acc, &bpa)) != 0) /* relocate addr */ | |
return tr; | |
if (bva & 2) | |
*dat = M[bpa >> 2] & HMASK; | |
else *dat = (M[bpa >> 2] >> 16) & HMASK; | |
} /* end else memory */ | |
return 0; | |
} | |
uint32 ReadW (uint32 bva, uint32 *dat, uint32 acc) | |
{ | |
uint32 bpa, tr; | |
if (bva < BVA_REG) /* register access */ | |
*dat = R[bva >> 2]; | |
else { /* memory access */ | |
if ((tr = map_reloc (bva, acc, &bpa)) != 0) /* relocate addr */ | |
return tr; | |
*dat = M[bpa >> 2]; | |
} /* end else memory */ | |
return 0; | |
} | |
uint32 ReadD (uint32 bva, uint32 *dat, uint32 *dat1, uint32 acc) | |
{ | |
uint32 bpa, tr; | |
if (bva < BVA_REG) { /* register access */ | |
*dat = R[(bva >> 2) & ~1]; /* force alignment */ | |
*dat1 = R[(bva >> 2) | 1]; | |
} | |
else { /* memory access */ | |
if ((tr = map_reloc (bva, acc, &bpa)) != 0) /* relocate addr */ | |
return tr; | |
*dat = M[(bpa >> 2) & ~1]; /* force alignment */ | |
*dat1 = M[(bpa >> 2) | 1]; | |
} /* end else memory */ | |
return 0; | |
} | |
uint32 WriteB (uint32 bva, uint32 dat, uint32 acc) | |
{ | |
uint32 bpa, sc, tr; | |
sc = 24 - ((bva & 3) << 3); | |
if (bva < BVA_REG) /* register access */ | |
R[bva >> 2] = (R[bva >> 2] & ~(BMASK << sc)) | ((dat & BMASK) << sc); | |
else { /* memory access */ | |
if ((tr = map_reloc (bva, acc, &bpa)) != 0) /* relocate addr */ | |
return tr; | |
M[bpa >> 2] = (M[bpa >> 2] & ~(BMASK << sc)) | ((dat & BMASK) << sc); | |
} /* end else memory */ | |
PSW2 |= PSW2_RA; /* state altered */ | |
return 0; | |
} | |
uint32 WriteH (uint32 bva, uint32 dat, uint32 acc) | |
{ | |
uint32 bpa, tr; | |
if (bva < BVA_REG) { /* register access */ | |
if (bva & 2) | |
R[bva >> 2] = (R[bva >> 2] & ~HMASK) | (dat & HMASK); | |
else R[bva >> 2] = (R[bva >> 2] & HMASK) | ((dat & HMASK) << 16); | |
} /* end if register */ | |
else { /* memory access */ | |
if ((tr = map_reloc (bva, acc, &bpa)) != 0) /* relocate addr */ | |
return tr; | |
if (bva & 2) | |
M[bpa >> 2] = (M[bpa >> 2] & ~HMASK) | (dat & HMASK); | |
else M[bpa >> 2] = (M[bpa >> 2] & HMASK) | ((dat & HMASK) << 16); | |
} /* end else memory */ | |
PSW2 |= PSW2_RA; /* state altered */ | |
return 0; | |
} | |
uint32 WriteW (uint32 bva, uint32 dat, uint32 acc) | |
{ | |
uint32 bpa, tr; | |
if (bva < BVA_REG) /* register access */ | |
R[bva >> 2] = dat & WMASK; | |
else { /* memory access */ | |
if ((tr = map_reloc (bva, acc, &bpa)) != 0) /* relocate addr */ | |
return tr; | |
M[bpa >> 2] = dat & WMASK; | |
} /* end else memory */ | |
PSW2 |= PSW2_RA; /* state altered */ | |
return 0; | |
} | |
uint32 WriteD (uint32 bva, uint32 dat, uint32 dat1, uint32 acc) | |
{ | |
uint32 bpa, tr; | |
if (bva < BVA_REG) { /* register access */ | |
R[(bva >> 2) & ~1] = dat & WMASK; /* force alignment */ | |
R[(bva >> 2) | 1] = dat1 & WMASK; | |
} | |
else { /* memory access */ | |
if ((tr = map_reloc (bva, acc, &bpa)) != 0) /* relocate addr */ | |
return tr; | |
M[(bpa >> 2) & ~1] = dat & WMASK; /* force alignment */ | |
M[(bpa >> 2) | 1] = dat1 & WMASK; | |
} /* end else memory */ | |
PSW2 |= PSW2_RA; /* state altered */ | |
return 0; | |
} | |
/* General virtual read for instruction history */ | |
uint32 ReadHist (uint32 bva, uint32 *dat, uint32 *dat1, uint32 acc, uint32 lnt) | |
{ | |
switch (lnt) { /* case on length */ | |
case BY: /* byte */ | |
return ReadB (bva, dat, acc); | |
case HW: /* halfword */ | |
return ReadH (bva, dat, acc); | |
case WD: /* word */ | |
return ReadW (bva, dat, acc); | |
case DW: /* doubleword first */ | |
return ReadD (bva, dat, dat1, acc); | |
} /* end case length */ | |
return SCPE_IERR; | |
} | |
/* Specialized virtual read and write word routines - | |
treats all addresses as memory addresses */ | |
uint32 ReadMemVW (uint32 bva, uint32 *dat, uint32 acc) | |
{ | |
uint32 bpa; | |
uint32 tr; | |
if ((tr = map_reloc (bva, acc, &bpa)) != 0) /* relocate addr */ | |
return tr; | |
*dat = M[bpa >> 2] & WMASK; | |
return 0; | |
} | |
uint32 WriteMemVW (uint32 bva, uint32 dat, uint32 acc) | |
{ | |
uint32 bpa; | |
uint32 tr; | |
if ((tr = map_reloc (bva, acc, &bpa)) != 0) /* relocate addr */ | |
return tr; | |
M[bpa >> 2] = dat & WMASK; | |
return 0; | |
} | |
/* Relocation routine */ | |
uint32 map_reloc (uint32 bva, uint32 acc, uint32 *bpa) | |
{ | |
if ((acc != 0) && (PSW1 & PSW1_MM)) { /* virt, map on? */ | |
uint32 vpag = BVA_GETPAG (bva); /* virt page num */ | |
*bpa = ((mmc_rel[vpag] << BVA_V_PAG) + BVA_GETOFF (bva)) & BPAMASK; | |
if (((PSW1 & PSW1_MS) || /* slave mode? */ | |
(PSW2 & (PSW2_MA9|PSW2_MA5X0))) && /* master prot? */ | |
(mmc_acc[vpag] >= acc)) /* access viol? */ | |
return map_viol (bva, *bpa, TR_MPR); | |
} | |
else *bpa = bva; /* no, physical */ | |
if ((acc == VW) && PSW2_WLK) { /* write check? */ | |
uint32 ppag = BPA_GETPAG (*bpa); /* phys page num */ | |
if (PSW2_WLK && mmc_wlk[ppag] && /* lock, key != 0 */ | |
(PSW2_WLK != mmc_wlk[ppag])) /* lock != key? */ | |
return map_viol (bva, *bpa, TR_WLK); | |
} | |
if (BPA_IS_NXM (*bpa)) /* memory exist? */ | |
return TR_NXM; /* don't set TSF */ | |
return 0; | |
} | |
/* Memory management error */ | |
uint32 map_viol (uint32 bva, uint32 bpa, uint32 tr) | |
{ | |
uint32 vpag = BVA_GETPAG (bva); /* virt page num */ | |
if (QCPU_S9) /* Sigma 9? */ | |
PSW2 = (PSW2 & ~PSW2_TSF) | (vpag << PSW2_V_TSF); /* save address */ | |
PSW4 = bva >> 2; /* 5X0 address */ | |
if ((tr == TR_WLK) && !QCPU_5X0) /* wlock on S5-9? */ | |
tr = TR_MPR; /* mem prot trap */ | |
if (BPA_IS_NXM (bpa)) /* also check NXM */ | |
tr |= TR_NXM; /* on MPR or WLK */ | |
return tr; | |
} | |
/* Physical byte access routines */ | |
uint32 ReadPB (uint32 ba, uint32 *wd) | |
{ | |
uint32 sc; | |
ba = ba & BPAMASK; | |
if (BPA_IS_NXM (ba)) | |
return TR_NXM; | |
sc = 24 - ((ba & 3) << 3); | |
*wd = (M[ba >> 2] >> sc) & BMASK; | |
return 0; | |
} | |
uint32 WritePB (uint32 ba, uint32 wd) | |
{ | |
uint32 sc; | |
ba = ba & BPAMASK; | |
if (BPA_IS_NXM (ba)) | |
return TR_NXM; | |
sc = 24 - ((ba & 3) << 3); | |
M[ba >> 2] = (M[ba >> 2] & ~(BMASK << sc)) | ((wd & BMASK) << sc); | |
return 0; | |
} | |
/* Physical word access routines */ | |
uint32 ReadPW (uint32 pa, uint32 *wd) | |
{ | |
pa = pa & cpu_tab[cpu_model].pamask; | |
if (MEM_IS_NXM (pa)) | |
return TR_NXM; | |
*wd = M[pa]; | |
return 0; | |
} | |
uint32 WritePW (uint32 pa, uint32 wd) | |
{ | |
pa = pa & cpu_tab[cpu_model].pamask; | |
if (MEM_IS_NXM (pa)) | |
return TR_NXM; | |
M[pa] = wd; | |
return 0; | |
} | |
/* LRA - load real address (extended memory systems only) */ | |
uint32 map_lra (uint32 rn, uint32 IR) | |
{ | |
uint32 lnt, bva, bpa, vpag, ppag; | |
uint32 tr; | |
lnt = CC >> 2; /* length */ | |
CC = 0; /* clear */ | |
if ((tr = Ea (IR, &bva, VR, lnt)) != 0) { /* get eff addr */ | |
if (tr == TR_NXM) /* NXM trap? */ | |
CC = CC1|CC2; | |
R[rn] = bva >> 2; /* fails */ | |
} | |
else if (bva < BVA_REG) { /* reg ref? */ | |
CC = CC1|CC2; | |
R[rn] = bva >> 2; /* fails */ | |
} | |
else { | |
vpag = BVA_GETPAG (bva); /* virt page num */ | |
bpa = ((mmc_rel[vpag] << BVA_V_PAG) + BVA_GETOFF (bva)) & BPAMASK; | |
ppag = BPA_GETPAG (bpa); /* phys page num */ | |
if (MEM_IS_NXM (bpa)) /* NXM? */ | |
CC = CC1|CC2; | |
R[rn] = (QCPU_S9? (mmc_wlk[ppag] << 24): 0) | /* result */ | |
(bpa >> lnt); | |
CC |= mmc_acc[vpag]; /* access prot */ | |
} | |
return 0; | |
} | |
/* MMC - load memory map control */ | |
uint32 map_mmc (uint32 rn, uint32 map) | |
{ | |
uint32 tr; | |
uint32 wd, i, map_width, maps_per_word, map_cmask, cs; | |
map_width = mmc_tab[map].width; /* width in bits */ | |
maps_per_word = 32 / map_width; | |
if (map != 1) /* maps 2-7? */ | |
map_cmask = mmc_tab[map].cmask; /* std ctl mask */ | |
else map_cmask = cpu_tab[cpu_model].mmc_cm_map1; /* model based */ | |
if ((map_width == 0) || /* validate map */ | |
((cpu_unit.flags & mmc_tab[map].opt) == 0) || | |
((map == 3) && !QCPU_5X0) || | |
((map == 5) && !QCPU_BIGM)) { | |
if (QCPU_S89_5X0) /* S89, 5X0 trap */ | |
return TR_INVMMC; | |
return stop_op? STOP_ILLEG: 0; | |
} | |
do { | |
cs = (R[rn|1] >> MMC_V_CS) & map_cmask; /* ptr into map */ | |
if ((tr = ReadW ((R[rn] << 2) & BVAMASK, &wd, VR)) != 0) | |
return tr; | |
for (i = 0; i < maps_per_word; i++) { /* loop thru word */ | |
wd = ((wd << map_width) | (wd >> (32 - map_width))) & WMASK; | |
switch (map) { | |
case 1: case 3: /* write locks */ | |
mmc_wlk[cs] = wd & mmc_tab[map].dmask; | |
break; | |
case 2: /* access ctls */ | |
mmc_acc[cs] = wd & mmc_tab[map].dmask; | |
break; | |
case 4: case 5: /* relocation */ | |
mmc_rel[cs] = wd & mmc_tab[map].dmask; | |
break; | |
}; | |
cs = (cs + 1) % mmc_tab[map].lnt; /* incr mod lnt */ | |
} /* end for */ | |
R[rn] = (R[rn] + 1) & WMASK; /* incr mem ptr */ | |
R[rn|1] = (R[rn|1] & ~(MMC_CNT | (map_cmask << MMC_V_CS))) | | |
(((MMC_GETCNT (R[rn|1]) - 1) & MMC_M_CNT) << MMC_V_CNT) | | |
((cs & map_cmask) << MMC_V_CS); | |
} while (MMC_GETCNT (R[rn|1]) != 0); | |
return SCPE_OK; | |
} | |
/* LAS instruction (reused by LMS), without condition code settings */ | |
uint32 map_las (uint32 rn, uint32 bva) | |
{ | |
uint32 opnd, tr; | |
if ((bva < (RF_NUM << 2)) && QCPU_5X0) /* on 5X0, reg */ | |
ReadW (bva, &opnd, VR); /* refs ignored */ | |
else { /* go to mem */ | |
if ((tr = ReadMemVW (bva, &opnd, VR)) != 0) /* read word */ | |
return tr; | |
if ((tr = WriteMemVW (bva, opnd | WSIGN, VW)) != 0) /* set bit */ | |
return tr; | |
} | |
R[rn] = opnd; /* store */ | |
return 0; | |
} | |
/* Load memory status */ | |
uint32 map_lms (uint32 rn, uint32 bva) | |
{ | |
uint32 tr, wd, low, ppag; | |
uint32 memu = (bva >> 2) / CPU_MUNIT_SIZE; | |
if (CC == 0) /* LAS */ | |
return map_las (rn, bva); | |
if (CC == 1) { /* read no par */ | |
if ((tr = ReadW (bva, &wd, PH)) != 0) | |
return tr; | |
R[rn] = wd; | |
for (CC = CC3; wd != 0; CC ^= CC3) { /* calc odd par */ | |
low = wd & -((int32) wd); | |
wd = wd & ~low; | |
} | |
return 0; | |
} | |
ppag = BPA_GETPAG (bva); /* phys page num */ | |
wd = mem_sr0[memu]; /* save sr0 */ | |
if (QCPU_S89) | |
switch (CC) { /* Sigma 8-9 */ | |
case 0x2: /* read bad par */ | |
if ((tr = ReadW (bva, &wd, VR)) != 0) | |
return tr; | |
R[rn] = wd; | |
break; | |
case 0x7: /* set margins */ | |
mem_sr1[memu] = S89_SR1_FIXED | | |
((memu & S89_SR1_M_MEMU) << S89_SR1_V_MEMU) | | |
((R[rn] & S89_SR1_MARG) >> S89_SR1_MAROFF); | |
break; | |
case 0xB: /* read sr0, clr */ | |
mem_sr0[memu] = mem_sr1[memu] = 0; /* fall through */ | |
case 0x8: /* read sr0 */ | |
R[rn] = (wd & S89_SR0_RD) | | |
(((1u << (chan_num + 1)) - 1) << (S89_SR0_V_PORTS - (chan_num + 1))); | |
break; | |
case 0x9: /* read sr1 */ | |
R[rn] = mem_sr1[memu]; | |
break; | |
case 0xA: case 0xE: /* read sr2 */ | |
R[rn] = 0; | |
break; | |
case 0xF: /* clear word */ | |
return WriteW (bva, 0, VW); | |
break; | |
default: | |
mem_sr0[memu] |= S89_SR0_BADLMS; | |
break; | |
} | |
else switch (CC) { /* 5X0 */ | |
case 0x2: /* clear word */ | |
return WriteW (bva, 0, VW); | |
case 0x6: /* read wlk */ | |
R[rn] = (mmc_wlk[ppag & ~1] << 4) | mmc_wlk[ppag | 1]; | |
break; | |
case 0x7: /* write wlk */ | |
mmc_wlk[ppag & ~1] = (R[rn] >> 4) & 0xF; | |
mmc_wlk[ppag | 1] = R[rn] & 0xF; | |
break; | |
case 0xC: /* read sr0, clr */ | |
mem_sr0[memu] = 0; /* clr, fall through */ | |
case 0x8: /* read sr0 */ | |
R[rn] = S5X0_SR0_FIXED | (wd & S5X0_SR0_RD) | | |
(((1u << (chan_num + 1)) - 1) << (S5X0_SR0_V_PORTS - (chan_num + 1))); | |
break; | |
case 0xA: /* read sr1 */ | |
R[rn] = S5X0_SR1_FIXED | | |
((memu & S5X0_SR1_M_MEMU) << S5X0_SR1_V_MEMU) | | |
(memu << S5X0_SR1_V_SA); | |
break; | |
case 0xE: /* trash mem */ | |
return WriteW (bva, R[rn] & ~0xFF, VW); | |
default: | |
mem_sr0[memu] |= S5X0_SR0_BADLMS; | |
break; | |
} | |
return 0; | |
} | |
/* Device reset */ | |
t_stat map_reset (DEVICE *dptr) | |
{ | |
uint32 i; | |
for (i = 0; i < VA_NUM_PAG; i++) { /* clear mmc arrays */ | |
mmc_rel[i] = 0; | |
mmc_acc[i] = 0; | |
} | |
for (i = 0; i < PA_NUM_PAG; i++) | |
mmc_wlk[i] = 0; | |
return SCPE_OK; | |
} |