| 1 | /* hp2100_cpu5.c: HP 1000 RTE-6/VM VMA and RTE-IV EMA instructions\r |
| 2 | \r |
| 3 | Copyright (c) 2006, J. David Bryan\r |
| 4 | Copyright (c) 2007-2008, Holger Veit\r |
| 5 | \r |
| 6 | Permission is hereby granted, free of charge, to any person obtaining a\r |
| 7 | copy of this software and associated documentation files (the "Software"),\r |
| 8 | to deal in the Software without restriction, including without limitation\r |
| 9 | the rights to use, copy, modify, merge, publish, distribute, sublicense,\r |
| 10 | and/or sell copies of the Software, and to permit persons to whom the\r |
| 11 | Software is furnished to do so, subject to the following conditions:\r |
| 12 | \r |
| 13 | The above copyright notice and this permission notice shall be included in\r |
| 14 | all copies or substantial portions of the Software.\r |
| 15 | \r |
| 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r |
| 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r |
| 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\r |
| 19 | THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r |
| 20 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r |
| 21 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r |
| 22 | \r |
| 23 | Except as contained in this notice, the name of the authors shall not be\r |
| 24 | used in advertising or otherwise to promote the sale, use or other dealings\r |
| 25 | in this Software without prior written authorization from the authors.\r |
| 26 | \r |
| 27 | CPU5 RTE-6/VM and RTE-IV firmware option instructions\r |
| 28 | \r |
| 29 | 01-May-08 HV Fixed mapping bug in "cpu_ema_emap"\r |
| 30 | 21-Apr-08 JDB Added EMA support from Holger\r |
| 31 | 25-Nov-07 JDB Added TF fix from Holger\r |
| 32 | 07-Nov-07 HV VMACK diagnostic tests 1...32 passed\r |
| 33 | 19-Oct-07 JDB Corrected $LOC operand profile to OP_CCCACC\r |
| 34 | 03-Oct-07 HV Moved RTE-6/VM instrs from hp2100_cpu0.c\r |
| 35 | 26-Sep-06 JDB Created\r |
| 36 | \r |
| 37 | Primary references:\r |
| 38 | - HP 1000 M/E/F-Series Computers Technical Reference Handbook\r |
| 39 | (5955-0282, Mar-1980)\r |
| 40 | - HP 1000 M/E/F-Series Computers Engineering and Reference Documentation\r |
| 41 | (92851-90001, Mar-1981)\r |
| 42 | - Macro/1000 Reference Manual (92059-90001, Dec-1992)\r |
| 43 | \r |
| 44 | Additional references are listed with the associated firmware\r |
| 45 | implementations, as are the HP option model numbers pertaining to the\r |
| 46 | applicable CPUs.\r |
| 47 | */\r |
| 48 | \r |
| 49 | #include <setjmp.h>\r |
| 50 | #include "hp2100_defs.h"\r |
| 51 | #include "hp2100_cpu.h"\r |
| 52 | #include "hp2100_cpu1.h"\r |
| 53 | \r |
| 54 | \r |
| 55 | t_stat cpu_rte_vma (uint32 IR, uint32 intrq); /* RTE-6 VMA */\r |
| 56 | t_stat cpu_rte_ema (uint32 IR, uint32 intrq); /* RTE-IV EMA */\r |
| 57 | \r |
| 58 | \r |
| 59 | /* RTE-6/VM Virtual Memory Area Instructions\r |
| 60 | \r |
| 61 | RTE-6/VM (product number 92084A) introduced Virtual Memory Area (VMA)\r |
| 62 | instructions -- a superset of the RTE-IV EMA instructions. Different\r |
| 63 | microcode was supplied with the operating system that replaced the microcode\r |
| 64 | used with RTE-IV. Microcode was limited to the E/F-Series, and the M-Series\r |
| 65 | used software equivalents.\r |
| 66 | \r |
| 67 | Option implementation by CPU was as follows:\r |
| 68 | \r |
| 69 | 2114 2115 2116 2100 1000-M 1000-E 1000-F\r |
| 70 | ------ ------ ------ ------ ------ ------ ------\r |
| 71 | N/A N/A N/A N/A N/A 92084A 92084A\r |
| 72 | \r |
| 73 | The routines are mapped to instruction codes as follows:\r |
| 74 | \r |
| 75 | Instr. 1000-E/F Description\r |
| 76 | ------ -------- ----------------------------------------------\r |
| 77 | .PMAP 105240 Map VMA page into map register\r |
| 78 | $LOC 105241 Load on call\r |
| 79 | [test] 105242 [self test]\r |
| 80 | .SWP 105243 [Swap A and B registers]\r |
| 81 | .STAS 105244 [STA B; LDA SP]\r |
| 82 | .LDAS 105245 [LDA SP]\r |
| 83 | .MYAD 105246 [NOP in microcode]\r |
| 84 | .UMPY 105247 [Unsigned multiply and add]\r |
| 85 | \r |
| 86 | .IMAP 105250 Integer element resolve address and map\r |
| 87 | .IMAR 105251 Integer element resolve address\r |
| 88 | .JMAP 105252 Double integer element resolve address and map\r |
| 89 | .JMAR 105253 Double integer element resolve address\r |
| 90 | .LPXR 105254 Map pointer in P+1 plus offset in P+2\r |
| 91 | .LPX 105255 Map pointer in A/B plus offset in P+1\r |
| 92 | .LBPR 105256 Map pointer in P+1\r |
| 93 | .LBP 105257 Map pointer in A/B registers\r |
| 94 | \r |
| 95 | Notes:\r |
| 96 | \r |
| 97 | 1. The opcodes 105243-247 are undocumented and do not appear to be used in\r |
| 98 | any HP software.\r |
| 99 | \r |
| 100 | 2. The opcode list in the CE Handbook incorrectly shows 105246 as ".MYAD -\r |
| 101 | multiply 2 signed integers." The microcode listing shows that this\r |
| 102 | instruction was deleted, and the opcode is now a NOP.\r |
| 103 | \r |
| 104 | 3. RTE-IV EMA and RTE-6 VMA instructions shared the same address space, so\r |
| 105 | a given machine could run one or the other, but not both.\r |
| 106 | \r |
| 107 | Additional references:\r |
| 108 | - RTE-6/VM VMA/EMA Microcode Source (92084-18828, revision 3).\r |
| 109 | - RTE-6/VM Technical Specifications (92084-90015, Apr-1983).\r |
| 110 | - M/E/F-Series Computer Systems CE Handbook (5950-3767, Jul-1984).\r |
| 111 | */\r |
| 112 | \r |
| 113 | static const OP_PAT op_vma[16] = {\r |
| 114 | OP_N, OP_CCCACC, OP_N, OP_N, /* .PMAP $LOC [test] .SWAP */\r |
| 115 | OP_N, OP_N, OP_N, OP_K, /* .STAS .LDAS .MYAD .UMPY */\r |
| 116 | OP_A, OP_A, OP_A, OP_A, /* .IMAP .IMAR .JMAP .JMAR */\r |
| 117 | OP_AA, OP_A, OP_A, OP_N /* .LPXR .LPX .LBPR .LBP */\r |
| 118 | };\r |
| 119 | \r |
| 120 | /* some addresses in page0 of RTE-6/VM */\r |
| 121 | static const uint32 idx = 0001645;\r |
| 122 | static const uint32 xmata = 0001646;\r |
| 123 | static const uint32 xi = 0001647;\r |
| 124 | static const uint32 xeqt = 0001717;\r |
| 125 | static const uint32 vswp = 0001776;\r |
| 126 | static const uint32 umaps = 0003740;\r |
| 127 | static const uint32 page30 = 0074000;\r |
| 128 | static const uint32 page31 = 0076000;\r |
| 129 | static const uint32 ptemiss = 0176000;\r |
| 130 | \r |
| 131 | /* frequent constants in paging */\r |
| 132 | #define SUITMASK 0176000 \r |
| 133 | #define NILPAGE 0176000\r |
| 134 | #define PAGEIDX 0001777\r |
| 135 | #define MSEGMASK 0076000\r |
| 136 | #define RWPROT 0141777\r |
| 137 | \r |
| 138 | /* from scp.c */\r |
| 139 | extern int32 sim_step;\r |
| 140 | extern FILE* sim_log;\r |
| 141 | \r |
| 142 | /* MP abort handler */\r |
| 143 | extern jmp_buf save_env;\r |
| 144 | #define ABORT(val) longjmp (save_env, (val))\r |
| 145 | \r |
| 146 | /* microcode version of resolve(): allows a much higher # of indirection levels. Used for\r |
| 147 | instance for LBP microcode diagnostics which will check > 100 levels.\r |
| 148 | */ \r |
| 149 | #define VMA_INDMAX 200\r |
| 150 | \r |
| 151 | static t_stat vma_resolve (uint32 MA, uint32 *addr, t_bool debug)\r |
| 152 | {\r |
| 153 | uint32 i;\r |
| 154 | uint32 faultma = MA;\r |
| 155 | \r |
| 156 | for (i = 0; (i < VMA_INDMAX) && (MA & I_IA); i++) { /* resolve multilevel */\r |
| 157 | MA = ReadW (MA & VAMASK); /* follow address chain */\r |
| 158 | } \r |
| 159 | \r |
| 160 | if (MA & I_IA) {\r |
| 161 | if (debug)\r |
| 162 | fprintf(sim_deb,">>CPU VMA: vma_resolve indirect loop addr=%06o\n",faultma);\r |
| 163 | return STOP_IND; /* indirect loop */\r |
| 164 | }\r |
| 165 | \r |
| 166 | *addr = MA;\r |
| 167 | return SCPE_OK;\r |
| 168 | }\r |
| 169 | \r |
| 170 | /* $LOC\r |
| 171 | ASSEMBLER CALLING SEQUENCE:\r |
| 172 | \r |
| 173 | $MTHK NOP RETURN ADDRESS OF CALL (REDONE AFTER THIS ROUTINE)\r |
| 174 | JSB $LOC\r |
| 175 | .DTAB OCT LGPG# LOGICAL PAGE # AT WHICH THE NODE TO \r |
| 176 | * BE MAPPED IN BELONGS (0-31)\r |
| 177 | OCT RELPG RELATIVE PAGE OFFSET FROM BEGINING\r |
| 178 | * OF PARTITION OF WHERE THAT NODE RESIDES.\r |
| 179 | * (0 - 1023)\r |
| 180 | OCT RELBP RELATIVE PAGE OFFSET FROM BEGINING OF \r |
| 181 | * PARTITION OF WHERE BASE PAGE RESIDES\r |
| 182 | * (0 - 1023)\r |
| 183 | CNODE DEF .CNOD THIS IS THE ADDRESS OF CURRENT PATH # WORD\r |
| 184 | .ORD OCT XXXXX THIS NODE'S LEAF # (IE PATH #)\r |
| 185 | .NOD# OCT XXXXX THIS NODE'S ORDINAL # \r |
| 186 | */\r |
| 187 | \r |
| 188 | static t_stat cpu_vma_loc(OPS op,uint32 intrq,t_bool debug)\r |
| 189 | {\r |
| 190 | uint32 eqt,mls,pnod,lstpg,fstpg,rotsz,lgpg,relpg,relbp,matloc,ptnpg,physpg,cnt,pgs,umapr;\r |
| 191 | \r |
| 192 | eqt = ReadIO(xeqt,UMAP); /* get ID segment */\r |
| 193 | mls = ReadIO(eqt+33,SMAP); /* get word33 of alternate map */\r |
| 194 | if ((mls & 0x8000) == 0) { /* this is not an MLS prog! */\r |
| 195 | PC = err_PC;\r |
| 196 | if (debug)\r |
| 197 | fprintf(sim_deb,">>CPU VMA: cpu_vma_loc at P=%06o: not an MLS program\n", PC);\r |
| 198 | if (CTL (PRO)) ABORT (ABORT_PRO); /* allow an MP abort */\r |
| 199 | return STOP_HALT; /* FATAL error! */\r |
| 200 | }\r |
| 201 | \r |
| 202 | pnod = mls & 01777; /* get #pages of mem res nodes */\r |
| 203 | if (pnod == 0) { /* no pages? FATAL! */\r |
| 204 | PC = err_PC;\r |
| 205 | if (debug)\r |
| 206 | fprintf(sim_deb,">>CPU VMA: cpu_vma_loc at P=%06o: no mem resident pages\n", PC);\r |
| 207 | if (CTL (PRO)) ABORT (ABORT_PRO); /* allow an MP abort */\r |
| 208 | return STOP_HALT;\r |
| 209 | }\r |
| 210 | \r |
| 211 | lstpg = (ReadIO(eqt+29,SMAP) >> 10) - 1; /* last page# of code */\r |
| 212 | fstpg = ReadIO(eqt+23,SMAP) >> 10; /* index to 1st addr + mem nodes */\r |
| 213 | rotsz = fstpg - (ReadIO(eqt+22,SMAP) >> 10); /* #pages in root */\r |
| 214 | lgpg = op[0].word;\r |
| 215 | \r |
| 216 | /* lets do some consistency checks, CPU halt if they fail */\r |
| 217 | if (lstpg < lgpg || lgpg < fstpg) { /* assert LSTPG >= LGPG# >= FSTPG */\r |
| 218 | PC = err_PC;\r |
| 219 | if (debug) \r |
| 220 | fprintf(sim_deb,\r |
| 221 | ">>CPU VMA: $LOC at P=%06o: failed check LSTPG >= LGPG# >= FSTPG\n",PC);\r |
| 222 | if (CTL (PRO)) ABORT (ABORT_PRO); /* allow an MP abort */\r |
| 223 | return STOP_HALT;\r |
| 224 | }\r |
| 225 | \r |
| 226 | relpg = op[1].word;\r |
| 227 | if (pnod < relpg || relpg < (rotsz+1)) { /* assert #PNOD >= RELPG >= ROTSZ+1 */\r |
| 228 | PC = err_PC;\r |
| 229 | if (debug) \r |
| 230 | fprintf(sim_deb,\r |
| 231 | ">>CPU VMA: $LOC at %06o: failed check #PNOD >= RELPG >= ROTSZ+1\n",PC);\r |
| 232 | if (CTL (PRO)) ABORT (ABORT_PRO); /* allow an MP abort */\r |
| 233 | return STOP_HALT;\r |
| 234 | }\r |
| 235 | \r |
| 236 | relbp = op[2].word;\r |
| 237 | if (relbp != 0) /* assert RELBP == 0 OR */\r |
| 238 | if (pnod < relbp || relbp < (rotsz+1)) { /* #PNOD >= RELBP >= ROTSZ+1 */\r |
| 239 | PC = err_PC;\r |
| 240 | if (debug) \r |
| 241 | fprintf(sim_deb,\r |
| 242 | ">>CPU VMA: $LOC at P=%06o: failed check: #PNOD >= RELBP >= ROTSZ+1\n",PC);\r |
| 243 | if (CTL (PRO)) ABORT (ABORT_PRO); /* allow an MP abort */\r |
| 244 | return STOP_HALT;\r |
| 245 | }\r |
| 246 | \r |
| 247 | cnt = lstpg - lgpg + 1; /* #pages to map */\r |
| 248 | pgs = pnod - relpg + 1; /* #pages from start node to end of code */\r |
| 249 | if (pgs < cnt) cnt = pgs; /* ensure minimum, so not to map into EMA */\r |
| 250 | \r |
| 251 | matloc = ReadIO(xmata,UMAP); /* get MAT $LOC address */\r |
| 252 | ptnpg = ReadIO(matloc+3,SMAP) & 01777; /* index to start phys pg */\r |
| 253 | physpg = ptnpg + relpg; /* phys pg # of node */\r |
| 254 | umapr = 32 + lgpg; /* map register to start */\r |
| 255 | \r |
| 256 | /* do an XMS with AR=umapr,BR=physpg,XR=cnt */\r |
| 257 | if (debug)\r |
| 258 | fprintf(sim_deb,\r |
| 259 | ">>CPU VMA: $LOC map %d pgs from phys=%06o to mapr=%d\n",\r |
| 260 | cnt,physpg,umapr);\r |
| 261 | while (cnt != 0) {\r |
| 262 | dms_wmap (umapr, physpg); /* map pages of new overlay segment */\r |
| 263 | cnt = (cnt - 1) & DMASK;\r |
| 264 | umapr = (umapr + 1) & DMASK;\r |
| 265 | physpg = (physpg + 1) & DMASK;\r |
| 266 | }\r |
| 267 | \r |
| 268 | dms_wmap(32,relbp+ptnpg); /* map base page again */\r |
| 269 | WriteW(op[3].word,op[4].word); /* path# we are going to */\r |
| 270 | \r |
| 271 | PC = (PC - 8) & DMASK; /* adjust PC to return address */\r |
| 272 | /* word before the $LOC microinstr. */\r |
| 273 | PC = (ReadW(PC) - 1) & DMASK; /* but the call has to be rerun, */\r |
| 274 | /* so must skip back to the original call */\r |
| 275 | /* which will now lead to the real routine */\r |
| 276 | if (debug)\r |
| 277 | fprintf(sim_deb,">>CPU VMA: $LOC done: path#=%06o, P=%06o\n",op[4].word,PC);\r |
| 278 | return SCPE_OK;\r |
| 279 | }\r |
| 280 | \r |
| 281 | /* map pte into last page\r |
| 282 | return FALSE if page fault, nil flag in PTE or suit mismatch \r |
| 283 | return TRUE if suit match, physpg = physical page \r |
| 284 | or page=0 -> last+1 page\r |
| 285 | */\r |
| 286 | static t_bool cpu_vma_ptevl(uint32 pagid,uint32* physpg)\r |
| 287 | {\r |
| 288 | uint32 suit;\r |
| 289 | uint32 pteidx = pagid & 0001777; /* build index */\r |
| 290 | uint32 reqst = pagid & SUITMASK; /* required suit */\r |
| 291 | uint32 pteval = ReadW(page31 | pteidx); /* get PTE entry */\r |
| 292 | *physpg = pteval & 0001777; /* store physical page number */\r |
| 293 | suit = pteval & SUITMASK; /* suit number seen */\r |
| 294 | if (pteval == NILPAGE) return FALSE; /* NIL value in PTE */\r |
| 295 | return suit == reqst || !*physpg; /* good page or last+1 */\r |
| 296 | }\r |
| 297 | \r |
| 298 | /* handle page fault */\r |
| 299 | static t_stat cpu_vma_fault(uint32 x,uint32 y,int32 mapr,\r |
| 300 | uint32 ptepg,uint32 ptr,uint32 faultpc, t_bool debug)\r |
| 301 | {\r |
| 302 | uint32 pre = ReadIO(xi,UMAP); /* get program preamble */\r |
| 303 | uint32 ema = ReadIO(pre+2,UMAP); /* get address of $EMA$/$VMA$ */\r |
| 304 | WriteIO(ema,faultpc,UMAP); /* write addr of fault instr */\r |
| 305 | XR = x; /* X = faulting page */\r |
| 306 | YR = y; /* Y = faulting address for page */\r |
| 307 | \r |
| 308 | if (mapr>0)\r |
| 309 | dms_wmap(mapr+UMAP,ptepg); /* map PTE into specified user dmsmap */\r |
| 310 | \r |
| 311 | /* do a safety check: first instr of $EMA$/$VMA$ must be a DST instr */\r |
| 312 | if (ReadIO(ema+1,UMAP) != 0104400) {\r |
| 313 | if (debug) \r |
| 314 | fprintf(sim_deb, ">>CPU VMA: pg fault: no EMA/VMA user code present\n");\r |
| 315 | if (CTL (PRO)) ABORT (ABORT_PRO); /* allow an MP abort */\r |
| 316 | return STOP_HALT; /* FATAL: no EMA/VMA! */\r |
| 317 | }\r |
| 318 | \r |
| 319 | PC = (ema+1) & VAMASK; /* restart $EMA$ user code, */\r |
| 320 | /* will return to fault instruction */\r |
| 321 | \r |
| 322 | AR = (ptr >> 16) & DMASK; /* restore A, B */\r |
| 323 | BR = ptr & DMASK;\r |
| 324 | E = 0; /* enforce E = 0 */\r |
| 325 | if (debug)\r |
| 326 | fprintf(sim_deb, \r |
| 327 | ">>CPU VMA: Call pg fault OS exit, AR=%06o BR=%06o P=%06o\n",\r |
| 328 | AR, BR, PC);\r |
| 329 | return SCPE_OK;\r |
| 330 | }\r |
| 331 | \r |
| 332 | /* map in PTE into last page, return false, if page fault */\r |
| 333 | static t_bool cpu_vma_mapte(uint32* ptepg)\r |
| 334 | {\r |
| 335 | uint32 idext,idext2;\r |
| 336 | uint32 dispatch = ReadIO(vswp,UMAP) & 01777; /* get fresh dispatch flag */\r |
| 337 | t_bool swapflag = TRUE;\r |
| 338 | \r |
| 339 | if (dispatch == 0) { /* not yet set */\r |
| 340 | idext = ReadIO(idx,UMAP); /* go into IDsegment extent */\r |
| 341 | if (idext != 0) { /* is ema/vma program? */\r |
| 342 | dispatch = ReadWA(idext+1) & 01777; /* get 1st ema page: new vswp */\r |
| 343 | WriteIO(vswp,dispatch,UMAP); /* move into $VSWP */\r |
| 344 | idext2 = ReadWA(idext+2); /* get swap bit */\r |
| 345 | swapflag = (idext2 & 020000) != 0; /* bit 13 = swap bit */\r |
| 346 | }\r |
| 347 | }\r |
| 348 | \r |
| 349 | if (dispatch) { /* some page is defined */\r |
| 350 | dms_wmap(31 + UMAP,dispatch); /* map $VSWP to register 31 */\r |
| 351 | *ptepg = dispatch; /* return PTEPG# for later */\r |
| 352 | }\r |
| 353 | \r |
| 354 | return swapflag; /* true for swap bit set */\r |
| 355 | }\r |
| 356 | \r |
| 357 | /* .LBP\r |
| 358 | ASSEMBLER CALLING SEQUENCE:\r |
| 359 | \r |
| 360 | DLD PONTR TRANSLATE 32 BIT POINTER TO 15\r |
| 361 | JSB .LBP BIT POINTER.\r |
| 362 | <RETURN - B = LOGICAL ADDRESS, A = PAGID> \r |
| 363 | \r |
| 364 | 32 bit pointer:\r |
| 365 | ----------AR------------ -----BR-----\r |
| 366 | 15 14....10 9....4 3...0 15.10 9....0\r |
| 367 | L<----------------------------------- L=1 local reference bit\r |
| 368 | XXXXXXXX<------------------------- 5 bit unused\r |
| 369 | PPPPPP PPPPP PPPPP<------ 16 bit PAGEID\r |
| 370 | SSSSSS<------------------ SUIT# within PAGEID\r |
| 371 | PPPPP PPPPP<------ 10 bit PAGEID index into PTE\r |
| 372 | OOOOOO 10 bit OFFSET\r |
| 373 | */\r |
| 374 | \r |
| 375 | static t_stat cpu_vma_lbp(uint32 ptr,uint32 aoffset,uint32 faultpc,uint32 intrq,t_bool debug) \r |
| 376 | {\r |
| 377 | uint32 pagid,offset,ptrl,pgidx,ptepg;\r |
| 378 | uint16 p30,p31,suit;\r |
| 379 | t_stat reason = SCPE_OK;\r |
| 380 | uint32 faultab = ptr; /* remember A,B for page fault */\r |
| 381 | ptr += aoffset; /* add the offset e.g. for .LPX */\r |
| 382 | \r |
| 383 | if (debug)\r |
| 384 | fprintf(sim_deb,">>CPU VMA: cpu_vma_lbp: ptr=%o/%o\n",\r |
| 385 | (ptr>>16) & DMASK,ptr & DMASK);\r |
| 386 | \r |
| 387 | O = 0; /* clear overflow */\r |
| 388 | if (ptr & 0x80000000) { /* is it a local reference? */\r |
| 389 | ptrl = ptr & VAMASK;\r |
| 390 | if ((ptr&I_IA) && (reason = vma_resolve (ReadW (ptrl), &ptrl, debug)))\r |
| 391 | return reason; /* yes, resolve indirect ref */\r |
| 392 | BR = ptrl & VAMASK; /* address is local */\r |
| 393 | AR = (ptr >> 16) & DMASK; \r |
| 394 | if (debug)\r |
| 395 | fprintf(sim_deb,">>CPU VMA: cpu_vma_lbp: local ref AR=%06o BR=%06o\n",AR,BR);\r |
| 396 | return SCPE_OK;\r |
| 397 | }\r |
| 398 | \r |
| 399 | pagid = (ptr >> 10) & DMASK; /* extract page id (16 bit idx, incl suit*/\r |
| 400 | offset = ptr & 01777; /* and offset */\r |
| 401 | suit = pagid & SUITMASK; /* suit of page */\r |
| 402 | pgidx = pagid & PAGEIDX; /* index into PTE */\r |
| 403 | \r |
| 404 | if (!cpu_vma_mapte(&ptepg)) /* map in PTE */\r |
| 405 | return cpu_vma_fault(65535,ptemiss,-1,ptepg,faultab,faultpc, debug); /* oops, must init PTE */\r |
| 406 | \r |
| 407 | /* ok, we have the PTE mapped to page31 */\r |
| 408 | /* the microcode tries to reads two consecutive data pages into page30 and page31 */\r |
| 409 | \r |
| 410 | /* read the 1st page value from PTE */\r |
| 411 | p30 = ReadW(page31 | pgidx) ^ suit;\r |
| 412 | if (!p30) /* matched suit for 1st page */\r |
| 413 | return cpu_vma_fault(pagid,page30,30,ptepg,faultab,faultpc,debug);\r |
| 414 | \r |
| 415 | /* suit switch situation: 1st page is in last idx of PTE, then following page\r |
| 416 | * must be in idx 0 of PTE */\r |
| 417 | if (pgidx==01777) { /* suit switch situation */\r |
| 418 | pgidx = 0; /* select correct idx 0 */\r |
| 419 | suit = pagid+1; /* suit needs increment */\r |
| 420 | if (suit==0) { /* is it page 65536? */\r |
| 421 | offset += 02000; /* adjust to 2nd page */\r |
| 422 | suit = NILPAGE;\r |
| 423 | pgidx = 01777;\r |
| 424 | }\r |
| 425 | } else\r |
| 426 | pgidx++; /* select next page */\r |
| 427 | \r |
| 428 | p31 = ReadW(page31 | pgidx) ^ suit;\r |
| 429 | if (!p31) { /* matched suit for 2nd page */\r |
| 430 | dms_wmap(31+UMAP,p30);\r |
| 431 | if (p30 & SUITMASK)\r |
| 432 | return cpu_vma_fault(pagid,page30,30,ptepg,faultab,faultpc,debug);\r |
| 433 | if (!(p31 ^ NILPAGE)) /* suit is 63: fault */\r |
| 434 | return cpu_vma_fault(pagid+1,page31,31,ptepg,faultab,faultpc,debug);\r |
| 435 | \r |
| 436 | offset += 02000; /* adjust offset to last user map because */\r |
| 437 | /* the address requested page 76xxx */\r |
| 438 | } \r |
| 439 | else {\r |
| 440 | dms_wmap(30+UMAP,p30);\r |
| 441 | if (p30 & SUITMASK)\r |
| 442 | return cpu_vma_fault(pagid,page30,30,ptepg,faultab,faultpc,debug);\r |
| 443 | dms_wmap(31+UMAP,p31);\r |
| 444 | if (p31 & SUITMASK)\r |
| 445 | return cpu_vma_fault(pagid+1,page31,31,ptepg,faultab,faultpc,debug);\r |
| 446 | }\r |
| 447 | \r |
| 448 | AR = pagid; /* return pagid in A */\r |
| 449 | BR = page30+offset; /* mapped address in B */\r |
| 450 | if (debug)\r |
| 451 | fprintf(sim_deb,">>CPU VMA: cpu_vma_lbp: map done AR=%06o BR=%o6o\n",AR,BR);\r |
| 452 | return SCPE_OK;\r |
| 453 | }\r |
| 454 | \r |
| 455 | /* .PMAP\r |
| 456 | ASSEMBLER CALLING SEQUENCE:\r |
| 457 | \r |
| 458 | LDA UMAPR (MSEG - 31) \r |
| 459 | LDB PAGID (0-65535) \r |
| 460 | JSB .PMAP GO MAP IT IN\r |
| 461 | <ERROR RETURN> A-REG = REASON, NOTE 1\r |
| 462 | <RETURN A=A+1, B=B+1,E=0 >> SEE NOTE 2>\r |
| 463 | \r |
| 464 | NOTE 1 : IF BIT 15 OF A-REG SET, THEN ALL NORMAL BRANCHES TO THE \r |
| 465 | $EMA$/$VMA$ CODE WILL BE CHANGED TO P+1 EXIT. THE A-REG \r |
| 466 | WILL BE THE REASON THE MAPPING WAS NOT SUCCESSFUL IF BIT 15\r |
| 467 | OF THE A-REG WAS NOT SET.\r |
| 468 | THIS WAS DONE SO THAT A ROUTINE ($VMA$) CAN DO A MAPPING \r |
| 469 | WITHOUT THE POSSIBILITY OF BEING RE-CURRED. IT IS USED\r |
| 470 | BY $VMA$ AND PSTVM IN THE PRIVLEDGED MODE. \r |
| 471 | NOTE 2: E-REG WILL = 1 IF THE LAST+1 PAGE IS REQUESTED AND \r |
| 472 | MAPPED READ/WRITE PROTECTED ON A GOOD P+2 RETURN.\r |
| 473 | */\r |
| 474 | static t_stat cpu_vma_pmap(uint32 umapr,uint32 pagid, t_bool debug)\r |
| 475 | {\r |
| 476 | uint32 physpg, ptr, pgpte;\r |
| 477 | uint32 mapnm = umapr & 0x7fff; /* strip off bit 15 */\r |
| 478 | \r |
| 479 | if (debug)\r |
| 480 | fprintf(sim_deb, ">>CPU VMA: .PMAP AR=%06o(umapr) BR=%06o(pagid)\n",umapr,pagid);\r |
| 481 | \r |
| 482 | if (mapnm > 31) { /* check for invalid map register */\r |
| 483 | AR = 80; /* error: corrupt EMA/VMA system */\r |
| 484 | if (debug)\r |
| 485 | fprintf(sim_deb, ">>CPU VMA: .PMAP invalid mapr: AR=80, exit P+1\n");\r |
| 486 | return SCPE_OK; /* return exit PC+1 */\r |
| 487 | }\r |
| 488 | \r |
| 489 | ptr = (umapr << 16) | (pagid & DMASK); /* build the ptr argument for vma_fault */ \r |
| 490 | if (!cpu_vma_mapte(&pgpte)) { /* map the PTE */\r |
| 491 | if (umapr & 0x8000) {\r |
| 492 | XR = 65535;\r |
| 493 | YR = ptemiss;\r |
| 494 | if (debug)\r |
| 495 | fprintf(sim_deb, \r |
| 496 | ">>CPU VMA: .PMAP pg fault&bit15: XR=%06o YR=%06o, exit P+1\n",\r |
| 497 | XR, YR);\r |
| 498 | return SCPE_OK; /* use PC+1 error exit */\r |
| 499 | }\r |
| 500 | return cpu_vma_fault(65535,ptemiss,-1,pgpte,ptr,PC-1,debug); /* oops: fix PTE */\r |
| 501 | }\r |
| 502 | \r |
| 503 | /* PTE is successfully mapped to page31 and dmsmap[63] */\r |
| 504 | if (!cpu_vma_ptevl(pagid,&physpg)) {\r |
| 505 | if (umapr & 0x8000) {\r |
| 506 | XR = pagid;\r |
| 507 | YR = page31;\r |
| 508 | if (debug)\r |
| 509 | fprintf(sim_deb, \r |
| 510 | ">>CPU VMA: .PMAP pg map&bit15: XR=%06o YR=%06o, exit P+1\n",\r |
| 511 | XR, YR);\r |
| 512 | return SCPE_OK; /* use PC+1 error exit*/\r |
| 513 | }\r |
| 514 | return cpu_vma_fault(pagid,page31,31,pgpte,ptr,PC-1,debug); /* page not present */\r |
| 515 | }\r |
| 516 | \r |
| 517 | E = 1;\r |
| 518 | if (physpg == 0) /* last+1 page ? */\r |
| 519 | physpg = RWPROT; /* yes, use page 1023 RW/Protected */\r |
| 520 | else E = 0; /* normal page to map */\r |
| 521 | \r |
| 522 | dms_wmap(mapnm+UMAP,physpg); /* map page to user page reg */ \r |
| 523 | if (mapnm != 31) /* unless already unmapped, */\r |
| 524 | dms_wmap(31+UMAP,RWPROT); /* unmap PTE */\r |
| 525 | \r |
| 526 | AR = (umapr + 1) & DMASK; /* increment mapr for next call */\r |
| 527 | BR = (pagid + 1) & DMASK; /* increment pagid for next call */\r |
| 528 | O = 0; /* clear overflow */\r |
| 529 | PC = (PC + 1) & VAMASK; /* normal PC+2 return */\r |
| 530 | if (debug)\r |
| 531 | fprintf(sim_deb,">>CPU VMA: .PMAP map done: AR=%06o BR=%o6o exit P+2\n",AR,BR);\r |
| 532 | return SCPE_OK;\r |
| 533 | }\r |
| 534 | \r |
| 535 | /* array calc helper for .imar, .jmar, .imap, .jmap\r |
| 536 | ij=in_s: 16 bit descriptors\r |
| 537 | ij=in_d: 32 bit descriptors\r |
| 538 | \r |
| 539 | This helper expects mainly the following arguments:\r |
| 540 | dtbl: pointer to an array descriptor table\r |
| 541 | atbl: pointer to the table of actual subscripts\r |
| 542 | \r |
| 543 | where subscript table is the following:\r |
| 544 | atbl-> DEF last_subscript,I (point to single or double integer)\r |
| 545 | ...\r |
| 546 | DEF first subscript,I (point to single or double integer)\r |
| 547 | \r |
| 548 | where Descriptor_table is the following table: \r |
| 549 | dtbl-> DEC #dimensions\r |
| 550 | DEC/DIN next-to-last dimension (single or double integer)\r |
| 551 | ...\r |
| 552 | DEC/DIN first dimension (single or double integer)\r |
| 553 | DEC elementsize in words\r |
| 554 | DEC high,low offset from start of EMA to element(0,0...0)\r |
| 555 | \r |
| 556 | Note that subscripts are counting from 0\r |
| 557 | */\r |
| 558 | static t_stat cpu_vma_ijmar(OPSIZE ij,uint32 dtbl,uint32 atbl,uint32* dimret,\r |
| 559 | uint32 intrq,t_bool debug)\r |
| 560 | {\r |
| 561 | t_stat reason = SCPE_OK;\r |
| 562 | uint32 ndim,MA,i,ws;\r |
| 563 | int32 accu,ax,dx;\r |
| 564 | OP din;\r |
| 565 | int opsz = ij==in_d ? 2 : 1;\r |
| 566 | \r |
| 567 | ndim = ReadW(dtbl++); /* get #dimensions itself */\r |
| 568 | if (debug) {\r |
| 569 | fprintf(sim_deb, ">>CPU VMA array calc #dim=%d, size=%d\n",ndim,opsz);\r |
| 570 | fprintf(sim_deb, ">>CPU VMA: array actual subscripts (");\r |
| 571 | for (i=0; i<ndim; i++) {\r |
| 572 | MA = ReadW(atbl+i);\r |
| 573 | if (resolve (MA, &MA, intrq)) break;\r |
| 574 | din = ReadOp(MA,ij);\r |
| 575 | if (i>0) fputc(',',sim_deb);\r |
| 576 | fprintf(sim_deb,"%d",ij==in_d?INT32(din.dword) : INT16(din.word));\r |
| 577 | }\r |
| 578 | \r |
| 579 | fprintf(sim_deb,")\n>>CPU VMA: array descriptor table (");\r |
| 580 | if (ndim) {\r |
| 581 | for (i=0; i<ndim-1; i++) {\r |
| 582 | din = ReadOp(dtbl+i*opsz,ij);\r |
| 583 | if (i>0) fputc(',',sim_deb);\r |
| 584 | fprintf(sim_deb,"%d",ij==in_d?INT32(din.dword) : INT16(din.word));\r |
| 585 | }\r |
| 586 | i = dtbl+1+(ndim-1)*opsz;\r |
| 587 | ws = ReadW(i-1);\r |
| 588 | }\r |
| 589 | else {\r |
| 590 | i = dtbl;\r |
| 591 | ws = 1;\r |
| 592 | }\r |
| 593 | fprintf(sim_deb,")\n>>CPU VMA: array elemsz=%d base=%o/%o\n",\r |
| 594 | ws,ReadW(i),ReadW(i+1));\r |
| 595 | }\r |
| 596 | \r |
| 597 | if (dimret) *dimret = ndim; /* return dimensions */\r |
| 598 | if (ndim == 0) { /* no dimensions: */\r |
| 599 | AR = ReadW(dtbl++); /* return the array base itself */\r |
| 600 | BR = ReadW(dtbl);\r |
| 601 | if (debug)\r |
| 602 | fprintf(sim_deb,">>CPU VMA: #dim=0, AR=%06o, BR=%06o\n",AR,BR);\r |
| 603 | return SCPE_OK;\r |
| 604 | }\r |
| 605 | \r |
| 606 | /* calculate\r |
| 607 | * (...(An*Dn-1)+An-1)*Dn-2)+An-2....)+A2)*D1)+A1)*#words + Array base\r |
| 608 | * Depending on ij, Ax and Dx can be 16 or 32 bit\r |
| 609 | */\r |
| 610 | accu = 0;\r |
| 611 | while (ndim-- > 0) {\r |
| 612 | MA = ReadW(atbl++); /* get addr of subscript */\r |
| 613 | if ((reason = resolve (MA, &MA, intrq))) /* and resolve it */\r |
| 614 | return reason;\r |
| 615 | din = ReadOp(MA,ij); /* get actual subscript value */\r |
| 616 | ax = ij==in_d ? INT32(din.dword) : INT16(din.word);\r |
| 617 | accu += ax; /* add to accu */\r |
| 618 | \r |
| 619 | if (ndim==0) ij = in_s; /* #words is single */\r |
| 620 | din = ReadOp(dtbl,ij); /* get dimension from descriptor table */\r |
| 621 | if (ij==in_d) {\r |
| 622 | dx = INT32(din.dword); /* either get double or single dimension */\r |
| 623 | dtbl += 2;\r |
| 624 | } else {\r |
| 625 | dx = INT16(din.word);\r |
| 626 | dtbl++;\r |
| 627 | }\r |
| 628 | accu *= dx; /* multiply */\r |
| 629 | } \r |
| 630 | \r |
| 631 | din = ReadOp(dtbl,in_d); /* add base address */\r |
| 632 | accu += din.dword;\r |
| 633 | \r |
| 634 | AR = (accu >> 16) & DMASK; /* transfer to AB */\r |
| 635 | BR = accu & DMASK;\r |
| 636 | if (debug)\r |
| 637 | fprintf(sim_deb,">>CPU VMA: resulting virt addr=%o (AR=%06o, BR=%06o)\n",accu,AR,BR);\r |
| 638 | return reason;\r |
| 639 | }\r |
| 640 | \r |
| 641 | /*\r |
| 642 | * This is the main handler for the RTE6/VMA microcodes */\r |
| 643 | t_stat cpu_rte_vma (uint32 IR, uint32 intrq)\r |
| 644 | {\r |
| 645 | t_stat reason = SCPE_OK;\r |
| 646 | OPS op;\r |
| 647 | OP_PAT pattern;\r |
| 648 | uint32 entry,t32,ndim;\r |
| 649 | uint32 dtbl,atbl; /* descriptor table ptr, actual args ptr */\r |
| 650 | OP dop0,dop1;\r |
| 651 | uint32 pcsave = (PC+1) & VAMASK; /* save PC to check for redo in imap/jmap */\r |
| 652 | t_bool debug = DEBUG_PRI (cpu_dev, DEB_VMA);\r |
| 653 | \r |
| 654 | if ((cpu_unit.flags & UNIT_VMAOS) == 0) /* VMA/OS option installed? */\r |
| 655 | return cpu_rte_ema (IR, intrq); /* try EMA */\r |
| 656 | \r |
| 657 | entry = IR & 017; /* mask to entry point */\r |
| 658 | pattern = op_vma[entry]; /* get operand pattern */\r |
| 659 | \r |
| 660 | if (pattern != OP_N)\r |
| 661 | if (reason = cpu_ops (pattern, op, intrq)) /* get instruction operands */\r |
| 662 | return reason;\r |
| 663 | \r |
| 664 | if (debug) { /* debugging? */\r |
| 665 | fprintf (sim_deb, ">>CPU VMA: IR = %06o (", IR); /* print preamble and IR */\r |
| 666 | fprint_sym (sim_deb, err_PC, (t_value *) &IR, /* print instruction mnemonic */\r |
| 667 | NULL, SWMASK('M'));\r |
| 668 | fprintf (sim_deb, "), P = %06o, XEQT = %06o", /* print location and program ID */\r |
| 669 | err_PC, ReadW (xeqt));\r |
| 670 | \r |
| 671 | fprint_ops (pattern, op); /* print operands */\r |
| 672 | fputc ('\n', sim_deb); /* terminate line */\r |
| 673 | }\r |
| 674 | \r |
| 675 | switch (entry) { /* decode IR<3:0> */\r |
| 676 | \r |
| 677 | case 000: /* .PMAP 105240 (OP_N) */\r |
| 678 | reason = cpu_vma_pmap(AR,BR,debug); /* map pages */\r |
| 679 | break;\r |
| 680 | \r |
| 681 | case 001: /* $LOC 105241 (OP_CCCACC) */\r |
| 682 | reason = cpu_vma_loc(op,intrq,debug); /* handle the coroutine switch */\r |
| 683 | break;\r |
| 684 | \r |
| 685 | case 002: /* [test] 105242 (OP_N) */\r |
| 686 | XR = 3; /* refer to src code 92084-18828 rev 3 */\r |
| 687 | SR = 0102077; /* HLT 77 instruction */\r |
| 688 | YR = 1; /* ROMs correctly installed */\r |
| 689 | PC = (PC+1) & VAMASK; /* skip instr if VMA/EMA ROM installed */\r |
| 690 | break;\r |
| 691 | \r |
| 692 | case 003: /* [swap] 105243 (OP_N) */\r |
| 693 | t32 = AR; /* swap A and B registers */\r |
| 694 | AR = BR;\r |
| 695 | BR = t32;\r |
| 696 | break;\r |
| 697 | \r |
| 698 | case 004: /* [---] 105244 (OP_N) */\r |
| 699 | reason = stop_inst; /* fragment of dead code */\r |
| 700 | break; /* in microrom */\r |
| 701 | \r |
| 702 | case 005: /* [---] 105245 (OP_N) */\r |
| 703 | reason = stop_inst; /* fragment of dead code */\r |
| 704 | break; /* in microrom */\r |
| 705 | \r |
| 706 | case 006: /* [nop] 105246 (OP_N) */\r |
| 707 | break; /* do nothing */\r |
| 708 | \r |
| 709 | case 007: /* [umpy] 105247 (OP_K) */\r |
| 710 | t32 = AR * op[0].word; /* get multiplier */\r |
| 711 | t32 += BR; /* add B */\r |
| 712 | AR = (t32 >> 16) & DMASK; /* move result back to AB */\r |
| 713 | BR = t32 & DMASK;\r |
| 714 | O = 0; /* instr clears OV */\r |
| 715 | break;\r |
| 716 | \r |
| 717 | case 010: /* .IMAP 105250 (OP_A) */\r |
| 718 | dtbl = op[0].word; \r |
| 719 | atbl = PC;\r |
| 720 | if ((reason = cpu_vma_ijmar(in_s,dtbl,atbl,&ndim,intrq,debug))) /* calc the virt address to AB */\r |
| 721 | return reason;\r |
| 722 | t32 = (AR << 16) | (BR & DMASK);\r |
| 723 | if ((reason = cpu_vma_lbp(t32,0,PC-2,intrq,debug)))\r |
| 724 | return reason;\r |
| 725 | if (PC==pcsave) \r |
| 726 | PC = (PC+ndim) & VAMASK; /* adjust PC: skip ndim subscript words */\r |
| 727 | break;\r |
| 728 | \r |
| 729 | case 011: /* .IMAR 105251 (OP_A) */\r |
| 730 | dtbl = ReadW(op[0].word);\r |
| 731 | atbl = (op[0].word+1) & VAMASK;\r |
| 732 | reason = cpu_vma_ijmar(in_s,dtbl,atbl,0,intrq,debug); /* calc the virt address to AB */\r |
| 733 | break;\r |
| 734 | \r |
| 735 | case 012: /* .JMAP 105252 (OP_A) */\r |
| 736 | dtbl = op[0].word;\r |
| 737 | atbl = PC;\r |
| 738 | if ((reason = cpu_vma_ijmar(in_d,dtbl,atbl,&ndim,intrq,debug))) /* calc the virtual address to AB */\r |
| 739 | return reason;\r |
| 740 | t32 = (AR << 16) | (BR & DMASK);\r |
| 741 | if ((reason = cpu_vma_lbp(t32,0,PC-2,intrq,debug)))\r |
| 742 | return reason;\r |
| 743 | if (PC==pcsave)\r |
| 744 | PC = (PC + ndim) & VAMASK; /* adjust PC: skip ndim subscript dword ptr */\r |
| 745 | break;\r |
| 746 | \r |
| 747 | case 013: /* .JMAR 105253 (OP_A) */\r |
| 748 | dtbl = ReadW(op[0].word);\r |
| 749 | atbl = (op[0].word+1) & VAMASK;\r |
| 750 | reason = cpu_vma_ijmar(in_d,dtbl,atbl,0,intrq,debug); /* calc the virt address to AB */\r |
| 751 | break;\r |
| 752 | \r |
| 753 | case 014: /* .LPXR 105254 (OP_AA) */\r |
| 754 | dop0 = ReadOp(op[0].word,in_d); /* get pointer from arg */\r |
| 755 | dop1 = ReadOp(op[1].word,in_d); \r |
| 756 | t32 = dop0.dword + dop1.dword; /* add offset to it */ \r |
| 757 | reason = cpu_vma_lbp(t32,0,PC-3,intrq,debug);\r |
| 758 | break;\r |
| 759 | \r |
| 760 | case 015: /* .LPX 105255 (OP_A) */\r |
| 761 | t32 = (AR << 16) | (BR & DMASK); /* pointer in AB */\r |
| 762 | dop0 = ReadOp(op[0].word,in_d);\r |
| 763 | reason = cpu_vma_lbp(t32,dop0.dword,PC-2,intrq,debug);\r |
| 764 | break;\r |
| 765 | \r |
| 766 | case 016: /* .LBPR 105256 (OP_A) */\r |
| 767 | dop0 = ReadOp(op[0].word,in_d); /* get the pointer */\r |
| 768 | reason = cpu_vma_lbp(dop0.dword,0,PC-2,intrq,debug);\r |
| 769 | break;\r |
| 770 | \r |
| 771 | case 017: /* .LBP 105257 (OP_N) */\r |
| 772 | t32 = (AR << 16) | (BR & DMASK);\r |
| 773 | reason = cpu_vma_lbp(t32,0,PC-1,intrq,debug);\r |
| 774 | break;\r |
| 775 | }\r |
| 776 | \r |
| 777 | return reason;\r |
| 778 | }\r |
| 779 | \r |
| 780 | \r |
| 781 | /* RTE-IV Extended Memory Area Instructions\r |
| 782 | \r |
| 783 | The RTE-IV operating system (HP product number 92067A) introduced the\r |
| 784 | Extended Memory Area (EMA) instructions. EMA provided a mappable data area\r |
| 785 | up to one megaword in size. These three instructions accelerated data\r |
| 786 | accesses to variables stored in EMA partitions. Support was limited to\r |
| 787 | E/F-Series machines; M-Series machines used software equivalents.\r |
| 788 | \r |
| 789 | Option implementation by CPU was as follows:\r |
| 790 | \r |
| 791 | 2114 2115 2116 2100 1000-M 1000-E 1000-F\r |
| 792 | ------ ------ ------ ------ ------ ------ ------\r |
| 793 | N/A N/A N/A N/A N/A 92067A 92067A\r |
| 794 | \r |
| 795 | The routines are mapped to instruction codes as follows:\r |
| 796 | \r |
| 797 | Instr. 1000-E/F Description\r |
| 798 | ------ -------- ----------------------------------------------\r |
| 799 | .EMIO 105240 EMA I/O\r |
| 800 | MMAP 105241 Map physical to logical memory\r |
| 801 | [test] 105242 [self test]\r |
| 802 | .EMAP 105257 Resolve array element address\r |
| 803 | \r |
| 804 | Notes:\r |
| 805 | \r |
| 806 | 1. RTE-IV EMA and RTE-6 VMA instructions share the same address space, so a\r |
| 807 | given machine can run one or the other, but not both.\r |
| 808 | \r |
| 809 | Additional references:\r |
| 810 | - RTE-IVB Programmer's Reference Manual (92068-90004, Dec-1983).\r |
| 811 | - RTE-IVB Technical Specifications (92068-90013, Jan-1980).\r |
| 812 | */\r |
| 813 | \r |
| 814 | static const OP_PAT op_ema[16] = {\r |
| 815 | OP_AKA, OP_AKK, OP_N, OP_N, /* .EMIO MMAP [test] --- */\r |
| 816 | OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */\r |
| 817 | OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */\r |
| 818 | OP_N, OP_N, OP_N, OP_AAA /* --- --- --- .EMAP */\r |
| 819 | };\r |
| 820 | \r |
| 821 | /* calculate the 32 bit EMA subscript for an array */\r |
| 822 | static t_bool cpu_ema_resolve(uint32 dtbl,uint32 atbl,uint32* sum)\r |
| 823 | {\r |
| 824 | int32 sub, act, low, sz;\r |
| 825 | uint32 MA, base;\r |
| 826 | \r |
| 827 | int32 ndim = ReadW(dtbl++); /* # dimensions */\r |
| 828 | if (ndim < 0) return FALSE; /* invalid? */\r |
| 829 | \r |
| 830 | *sum = 0; /* accu for index calc */\r |
| 831 | while (ndim > 0) {\r |
| 832 | MA = ReadW(atbl++); /* get address of A(N) */\r |
| 833 | resolve (MA, &MA, 0);\r |
| 834 | act = ReadW(MA); /* A(N) */\r |
| 835 | low = ReadW(dtbl++); /* -L(N) */\r |
| 836 | sub = SEXT(act) + SEXT(low); /* subscript */\r |
| 837 | if (sub & 0xffff8000) return FALSE; /* overflow? */\r |
| 838 | *sum += sub; /* accumulate */\r |
| 839 | sz = ReadW(dtbl++);\r |
| 840 | sz = SEXT(sz);\r |
| 841 | if (sz < 0) return FALSE;\r |
| 842 | *sum *= sz;\r |
| 843 | if (*sum > (512*1024)) return FALSE; /* overflow? */\r |
| 844 | ndim--;\r |
| 845 | }\r |
| 846 | base = (ReadW(dtbl+1)<<16) | (ReadW(dtbl) & 0xffff); /* base of array in EMA */\r |
| 847 | if (base & 0x8000000) return FALSE;\r |
| 848 | *sum += base; /* calculate address into EMA */\r |
| 849 | if (*sum & 0xf8000000) return FALSE; /* overflow? */\r |
| 850 | return TRUE;\r |
| 851 | }\r |
| 852 | \r |
| 853 | /* implementation of VIS RTE-IVB EMA support\r |
| 854 | * .ERES microcode routine, resolves only EMA addresses\r |
| 855 | * Call:\r |
| 856 | * .OCT 101474B\r |
| 857 | * DEF RTN error return (rtn), good return is rtn+1\r |
| 858 | * DEF DUMMY dummy argument for compatibility with .EMAP\r |
| 859 | * DEF TABLE[,I] array declaration (dtbl)\r |
| 860 | * DEF A(N)[,I] actual subscripts (atbl)\r |
| 861 | * DEF A(N-1)[,I]\r |
| 862 | * ...\r |
| 863 | * DEF A(2)[,I]\r |
| 864 | * DEF A(1)[,I]\r |
| 865 | * RTN EQU * error return A="20", B="EM"\r |
| 866 | * RTN+1 EQU *+1 good return B=logical address\r |
| 867 | *\r |
| 868 | * TABLE DEC # # dimensions\r |
| 869 | * DEC -L(N)\r |
| 870 | * DEC D(N-1)\r |
| 871 | * DEC -L(N-1) lower bound (n-1)st dim\r |
| 872 | * DEC D(N-2) (n-2)st dim \r |
| 873 | * ...\r |
| 874 | * DEC D(1) 1st dim\r |
| 875 | * DEC -L(1) lower bound 1st dim\r |
| 876 | * DEC # # words/element\r |
| 877 | * OFFSET 1 EMA Low\r |
| 878 | * OFFSET 2 EMA High\r |
| 879 | */\r |
| 880 | t_stat cpu_ema_eres(uint32 *rtn,uint32 dtbl,uint32 atbl,t_bool debug)\r |
| 881 | {\r |
| 882 | uint32 sum;\r |
| 883 | if (cpu_ema_resolve(dtbl,atbl,&sum)) { /* calculate subscript */\r |
| 884 | AR = sum & 0xffff;\r |
| 885 | BR = sum >> 16;\r |
| 886 | if (!(BR & SIGN)) { /* no overflow? */\r |
| 887 | (*rtn)++; /* return via good exit */\r |
| 888 | return SCPE_OK;\r |
| 889 | }\r |
| 890 | }\r |
| 891 | AR = 0x3230; /* error condition: */\r |
| 892 | BR = 0x454d; /* AR = '20', BR = 'EM' */\r |
| 893 | return SCPE_OK; /* return via unmodified rtn */\r |
| 894 | } \r |
| 895 | \r |
| 896 | /* implementation of VIS RTE-IVB EMA support\r |
| 897 | * .ESEG microcode routine\r |
| 898 | * Call:\r |
| 899 | * LDA FIRST first map to set\r |
| 900 | * LDB N # of maps to set\r |
| 901 | * .OCT 101475B/105475B\r |
| 902 | * DEF RTN ptr to return\r |
| 903 | * DEF TABLE map table\r |
| 904 | * RTN EQU * error return A="21", B="EM"\r |
| 905 | * RTN+1 EQU *+1 good return B=logical address\r |
| 906 | *\r |
| 907 | * load maps FIRST to FIRST+N from TABLE, with FIRST = FIRST + LOG_START MSEG\r |
| 908 | * update map table in base page. Set LOG_START MSEG=0 if opcode==105475\r |
| 909 | */\r |
| 910 | t_stat cpu_ema_eseg(uint32* rtn, uint32 IR, uint32 tbl, t_bool debug)\r |
| 911 | {\r |
| 912 | uint32 xidex,eqt,idext0,idext1;\r |
| 913 | uint32 msegsz,phys,msegn,last,emasz,pg0,pg1,pg,i,lp;\r |
| 914 | \r |
| 915 | if ((BR & SIGN) || BR==0) goto em21; /* #maps not positive? */\r |
| 916 | xidex = ReadIO(idx,UMAP); /* read ID extension */\r |
| 917 | if (xidex==0) goto em21;\r |
| 918 | idext0 = ReadWA(xidex+0); /* get 1st word idext */\r |
| 919 | msegsz = idext0 & 037; /* S7 MSEG size */\r |
| 920 | WriteIO(xidex+0, idext0 | 0100000, SMAP); /* enforce nonstd MSEG */\r |
| 921 | idext1 = ReadWA(xidex+1); /* get 2nd word idext */\r |
| 922 | phys = idext1 & 01777; /* S5 phys start of EMA */\r |
| 923 | msegn = (idext1 >> 11) & 037; /* S9 get logical start MSEG# */\r |
| 924 | if (IR & 04000) { /* opcode == 105475? (.VPRG) */\r |
| 925 | msegn = 0; /* log start = 0 */\r |
| 926 | msegsz = 32; /* size = full range */\r |
| 927 | }\r |
| 928 | last = AR-1 + BR; /* last page */\r |
| 929 | if (last > msegsz) goto em21; /* too many? error */\r |
| 930 | eqt = ReadIO(xeqt,UMAP);\r |
| 931 | emasz = (ReadWA(eqt+28) & 01777) - 1; /* S6 EMA size in pages */\r |
| 932 | \r |
| 933 | /* locations 1740...1777 of user base page contain the map entries we need.\r |
| 934 | * They are normally hidden by BP fence, therefore they have to be accessed by\r |
| 935 | * another fence-less map register. uCode uses #1 temporarily */\r |
| 936 | pg0 = dms_rmap(UMAP+0); /* read map #0 */\r |
| 937 | pg1 = dms_rmap(UMAP+1); /* save map #1 */\r |
| 938 | dms_wmap(UMAP+1,pg0); /* copy #0 into reg #1 */\r |
| 939 | lp = AR + msegn; /* first */\r |
| 940 | for (i=0; i<BR; i++) { /* loop over N entries */\r |
| 941 | pg = ReadW(tbl++); /* get value from table */\r |
| 942 | if ((pg & SIGN) || pg > emasz) pg |= 0140000; /* write protect if outside */\r |
| 943 | pg += phys; /* adjust into EMA page range */\r |
| 944 | WriteIO(umaps+lp+i, pg, UMAP); /* copy pg to user map */\r |
| 945 | //printf("MAP val %oB to reg %d (addr=%oB)\n",pg,lp+i,umaps+lp+i);\r |
| 946 | dms_wmap(UMAP+lp+i, pg); /* set DMS reg */\r |
| 947 | }\r |
| 948 | dms_wmap(UMAP+1,pg1); /* restore map #1 */\r |
| 949 | O = 0; /* clear overflow */\r |
| 950 | (*rtn)++; /* return via good exit */\r |
| 951 | return SCPE_OK;\r |
| 952 | \r |
| 953 | em21:\r |
| 954 | AR = 0x3231; /* error condition: */\r |
| 955 | BR = 0x454d; /* AR = '21', BR = 'EM' */\r |
| 956 | return SCPE_OK; /* return via unmodified rtn */\r |
| 957 | }\r |
| 958 | \r |
| 959 | /* implementation of VIS RTE-IVB EMA support\r |
| 960 | * .VSET microcode routine\r |
| 961 | * Call:\r |
| 962 | * .OCT 101476B\r |
| 963 | * DEF RTN return address\r |
| 964 | * DEF VIN input vector\r |
| 965 | * DEF VOUT output vector\r |
| 966 | * DEF MAPS\r |
| 967 | * OCT #SCALARS\r |
| 968 | * OCT #VECTORS\r |
| 969 | * OCT K 1024/(#words/element)\r |
| 970 | * RTN EQU * error return (B,A) = "VI22"\r |
| 971 | * RTN+1 EQU *+1 hard return, A = K/IMAX\r |
| 972 | * RTN+2 EQU *+2 easy return, A = 0, B = 2* #VCTRS\r |
| 973 | */\r |
| 974 | t_stat cpu_ema_vset(uint32* rtn, OPS op, t_bool debug)\r |
| 975 | {\r |
| 976 | uint32 vin = op[0].word; /* S1 */\r |
| 977 | uint32 vout = op[1].word; /* S2 */\r |
| 978 | uint32 maps = op[2].word; /* S3 */\r |
| 979 | uint32 scalars = op[3].word; /* S4 */\r |
| 980 | uint32 vectors = op[4].word; /* S5 */\r |
| 981 | uint32 k = op[5].word; /* S6 */\r |
| 982 | uint32 imax = 0; /* imax S11*/\r |
| 983 | uint32 xidex,idext1,mseg,phys, addr, i, MA;\r |
| 984 | t_bool negflag = FALSE;\r |
| 985 | \r |
| 986 | for (i=0; i<scalars; i++) { /* copy scalars */\r |
| 987 | XR = ReadW(vin++);\r |
| 988 | WriteW(vout++, XR);\r |
| 989 | }\r |
| 990 | xidex = ReadIO(idx,UMAP); /* get ID extension */\r |
| 991 | if (xidex==0) goto vi22; /* NO EMA? error */\r |
| 992 | idext1 = ReadWA(xidex+1);\r |
| 993 | mseg = (idext1 >> 1) & MSEGMASK; /* S9 get logical start MSEG */\r |
| 994 | phys = idext1 & 01777; /* phys start of EMA */\r |
| 995 | \r |
| 996 | for (i=0; i<vectors; i++) { /* copy vector addresses */\r |
| 997 | MA = ReadW(vin++);\r |
| 998 | resolve (MA, &MA, 0);\r |
| 999 | addr = ReadW(MA) & 0177777; /* LSB */\r |
| 1000 | addr |= (ReadW(MA+1)<<16); /* MSB, build address */\r |
| 1001 | WriteW(vout++, mseg + (addr & 01777)); /* build and write log addr of vector */\r |
| 1002 | addr = (addr >> 10) & 0xffff; /* get page */\r |
| 1003 | WriteW(maps++, addr); /* save page# */\r |
| 1004 | WriteW(maps++, addr+1); /* save next page# as well */\r |
| 1005 | MA = ReadW(vin++); /* get index into Y */\r |
| 1006 | resolve(MA, &MA, 0);\r |
| 1007 | YR = ReadW(MA); /* get index value */\r |
| 1008 | WriteW(vout++, MA); /* copy address of index */\r |
| 1009 | if (YR & SIGN) { /* index is negative */\r |
| 1010 | negflag = TRUE; /* mark a negative index (HARD) */\r |
| 1011 | YR = (~YR + 1) & DMASK; /* make index positive */\r |
| 1012 | }\r |
| 1013 | if (imax < YR) imax = YR; /* set maximum index */\r |
| 1014 | mseg += 04000; /* incr mseg address by 2 more pages */ \r |
| 1015 | }\r |
| 1016 | MA = ReadW(vin); /* get N index into Y */\r |
| 1017 | resolve(MA, &MA, 0);\r |
| 1018 | YR = ReadW(MA);\r |
| 1019 | WriteW(vout++, MA); vin++; /* copy address of N */\r |
| 1020 | \r |
| 1021 | if (imax==0) goto easy; /* easy case */\r |
| 1022 | AR = k / imax; AR++; /* calculate K/IMAX */\r |
| 1023 | if (negflag) goto hard; /* had a negative index? */\r |
| 1024 | if (YR > AR) goto hard;\r |
| 1025 | \r |
| 1026 | easy:\r |
| 1027 | (*rtn)++; /* return via exit 2 */\r |
| 1028 | AR = 0;\r |
| 1029 | \r |
| 1030 | hard:\r |
| 1031 | (*rtn)++; /* return via exit 1 */\r |
| 1032 | BR = 2 * op[4].word; /* B = 2* vectors */\r |
| 1033 | return SCPE_OK;\r |
| 1034 | \r |
| 1035 | vi22: /* error condition */\r |
| 1036 | AR=0x3232; /* AR = '22' */ \r |
| 1037 | BR=0x5649; /* BR = 'VI' */\r |
| 1038 | return SCPE_OK; /* return via unmodified e->rtn */\r |
| 1039 | }\r |
| 1040 | \r |
| 1041 | typedef struct ema4 {\r |
| 1042 | uint32 mseg; /* logical start of MSEG */\r |
| 1043 | uint32 msegsz; /* size of std mseg in pgs */\r |
| 1044 | uint32 pgoff; /* pg # in EMA containing element */\r |
| 1045 | uint32 offs; /* offset into page of element */\r |
| 1046 | uint32 msoff; /* total offset to element in MSEG */\r |
| 1047 | uint32 emasz; /* size of ema in pgs */\r |
| 1048 | uint32 msegno; /* # of std mseg */\r |
| 1049 | uint32 ipgs; /* # of pgs to start of MSEG */\r |
| 1050 | uint32 npgs; /* # of pgs needed */\r |
| 1051 | uint32 spmseg; /* first phys pg of MSEG */\r |
| 1052 | } EMA4;\r |
| 1053 | \r |
| 1054 | static t_bool cpu_ema_emas(uint32 dtbl,uint32 atbl,EMA4* e)\r |
| 1055 | {\r |
| 1056 | uint32 xidex, eqt;\r |
| 1057 | uint32 sum, msegsz,pgoff,offs,emasz,msegno,msoff,ipgs;\r |
| 1058 | \r |
| 1059 | if (!cpu_ema_resolve(dtbl,atbl,&sum)) return FALSE; /* calculate 32 bit index */\r |
| 1060 | \r |
| 1061 | xidex = ReadIO(idx,UMAP); /* read ID extension */\r |
| 1062 | msegsz = ReadWA(xidex+0) & 037; /* S5 # pgs for std MSEG */\r |
| 1063 | pgoff = sum >> 10; /* S2 page containing element */\r |
| 1064 | offs = sum & 01777; /* S6 offset in page to element */\r |
| 1065 | if (pgoff > 1023) return FALSE; /* overflow? */\r |
| 1066 | eqt = ReadIO(xeqt,UMAP);\r |
| 1067 | emasz = ReadWA(eqt+28) & 01777; /* S EMA size in pages */\r |
| 1068 | if (pgoff > emasz) return FALSE; /* outside EMA? */\r |
| 1069 | msegno = pgoff / msegsz; /* S4 # of MSEG */\r |
| 1070 | msoff = pgoff % msegsz; /* offset within MSEG in pgs */\r |
| 1071 | ipgs = pgoff - msoff; /* S7 # pgs to start of MSEG */\r |
| 1072 | msoff = msoff << 10; /* offset within MSEG in words */\r |
| 1073 | msoff += offs; /* S1 offset to element in words */\r |
| 1074 | \r |
| 1075 | e->msegsz = msegsz; /* return calculated data */\r |
| 1076 | e->pgoff = pgoff;\r |
| 1077 | e->offs = offs;\r |
| 1078 | e->emasz = emasz;\r |
| 1079 | e->msegno = msegno;\r |
| 1080 | e->ipgs = ipgs;\r |
| 1081 | e->msoff = msoff;\r |
| 1082 | return TRUE;\r |
| 1083 | }\r |
| 1084 | \r |
| 1085 | static t_bool cpu_ema_mmap01(EMA4* e)\r |
| 1086 | {\r |
| 1087 | uint32 xidex,idext0, pg, pg0, pg1, i;\r |
| 1088 | \r |
| 1089 | uint32 base = e->mseg >> 10; /* get the # of first MSEG DMS reg */\r |
| 1090 | xidex = ReadIO(idx,UMAP); /* get ID extension */\r |
| 1091 | idext0 = ReadWA(xidex+1);\r |
| 1092 | \r |
| 1093 | if (e->npgs==0) return FALSE; /* no pages to map? */\r |
| 1094 | if ((e->npgs+1+e->ipgs) <= e->emasz) e->npgs++; /* actually map npgs+1 pgs */\r |
| 1095 | \r |
| 1096 | /* locations 1740...1777 of user base page contain the map entries we need.\r |
| 1097 | * They are normally hidden by BP fence, therefore they have to be accessed by\r |
| 1098 | * another fence-less map register. uCode uses #1, macro code uses $DVCT (==2)\r |
| 1099 | */\r |
| 1100 | pg0 = dms_rmap(UMAP+0); /* read base page map# */\r |
| 1101 | pg1 = dms_rmap(UMAP+1); /* save map# 1 */\r |
| 1102 | dms_wmap(UMAP+1,pg0); /* map #0 into reg #1 */\r |
| 1103 | for (i=0; (base+i)<32; i++) {\r |
| 1104 | pg = i<e->npgs ? e->spmseg : 0140000; /* write protect if outside */\r |
| 1105 | WriteIO(umaps+base+i, pg, UMAP); /* copy pg to user map */\r |
| 1106 | //printf("MAP val %d to reg %d (addr=%o)\n",pg,base+i,umaps+base+i);\r |
| 1107 | dms_wmap(UMAP+base+i, pg); /* set DMS reg */\r |
| 1108 | e->spmseg++;\r |
| 1109 | }\r |
| 1110 | dms_wmap(UMAP+1,pg1); /* restore map #1 */\r |
| 1111 | \r |
| 1112 | xidex = ReadIO(idx,UMAP); /* get ID extension */\r |
| 1113 | idext0 = ReadWA(xidex+0);\r |
| 1114 | if (e->msegno == 0xffff) /* non std mseg */\r |
| 1115 | idext0 |= 0x8000; /* set nonstd marker */\r |
| 1116 | else\r |
| 1117 | idext0 = (idext0 & 037) | (e->msegno<<5); /* set new current mseg# */\r |
| 1118 | WriteIO(xidex, idext0, SMAP); /* save back value */\r |
| 1119 | AR = 0; /* was successful */\r |
| 1120 | return TRUE;\r |
| 1121 | }\r |
| 1122 | \r |
| 1123 | static t_bool cpu_ema_mmap02(EMA4* e)\r |
| 1124 | {\r |
| 1125 | uint32 xidex, eqt, idext1;\r |
| 1126 | uint32 mseg,phys,spmseg,emasz,msegsz,msegno;\r |
| 1127 | \r |
| 1128 | xidex = ReadIO(idx,UMAP); /* get ID extension */\r |
| 1129 | msegsz = ReadWA(xidex+0) & 037; /* P size of std MSEG */\r |
| 1130 | idext1 = ReadWA(xidex+1);\r |
| 1131 | mseg = (idext1 >> 1) & MSEGMASK; /* S9 get logical start MSEG */\r |
| 1132 | phys = idext1 & 01777; /* S phys start of EMA */\r |
| 1133 | spmseg = phys + e->ipgs; /* S7 phys pg# of MSEG */\r |
| 1134 | msegno = e->ipgs / msegsz;\r |
| 1135 | if ((e->ipgs % msegsz) != 0) /* non std MSEG? */\r |
| 1136 | msegno = 0xffff; /* S4 yes, set marker */\r |
| 1137 | if (e->npgs > msegsz) return FALSE; /* map more pages than MSEG sz? */\r |
| 1138 | eqt = ReadIO(xeqt,UMAP);\r |
| 1139 | emasz = ReadWA(eqt+28) & 01777; /* B EMA size in pages */\r |
| 1140 | if ((e->ipgs+e->npgs) > emasz) return FALSE; /* outside EMA? */ \r |
| 1141 | if ((e->ipgs+msegsz) > emasz) /* if MSEG overlaps end of EMA */\r |
| 1142 | e->npgs = emasz - e->ipgs; /* only map until end of EMA */\r |
| 1143 | \r |
| 1144 | e->emasz = emasz; /* copy arguments */\r |
| 1145 | e->msegsz = msegsz;\r |
| 1146 | e->msegno = msegno;\r |
| 1147 | e->spmseg = spmseg;\r |
| 1148 | e->mseg = mseg;\r |
| 1149 | return cpu_ema_mmap01(e);\r |
| 1150 | }\r |
| 1151 | \r |
| 1152 | static t_stat cpu_ema_mmap(uint32 ipage,uint32 npgs, t_bool debug)\r |
| 1153 | {\r |
| 1154 | uint32 xidex;\r |
| 1155 | EMA4 ema4, *e = &ema4;\r |
| 1156 | \r |
| 1157 | e->ipgs = ipage; /* S6 set the arguments */\r |
| 1158 | e->npgs = npgs; /* S5 */\r |
| 1159 | \r |
| 1160 | AR = 0;\r |
| 1161 | xidex = ReadIO(idx,UMAP); \r |
| 1162 | if ((ipage & SIGN) || /* negative page displacement? */\r |
| 1163 | (npgs & SIGN) || /* negative # of pages? */\r |
| 1164 | xidex == 0 || /* no EMA? */\r |
| 1165 | !cpu_ema_mmap02(e)) /* mapping failed? */\r |
| 1166 | AR = 0177777; /* return with error */\r |
| 1167 | return SCPE_OK; /* leave */\r |
| 1168 | }\r |
| 1169 | \r |
| 1170 | static t_bool cpu_ema_emat(EMA4* e)\r |
| 1171 | {\r |
| 1172 | uint32 xidex,idext0;\r |
| 1173 | uint32 curmseg,phys,msnum,lastpgs;\r |
| 1174 | \r |
| 1175 | xidex = ReadIO(idx,UMAP); /* read ID extension */\r |
| 1176 | idext0 = ReadWA(xidex+0); /* get current segment */\r |
| 1177 | curmseg = idext0 >> 5;\r |
| 1178 | if ((idext0 & 0100000) || /* was nonstd MSEG? */\r |
| 1179 | curmseg != e->msegno) { /* or different MSEG last time? */\r |
| 1180 | phys = ReadWA(xidex+1) & 01777; /* physical start pg of EMA */\r |
| 1181 | e->spmseg = phys + e->ipgs; /* physical start pg of MSEG */\r |
| 1182 | msnum = e->emasz / e->msegsz; /* find last MSEG# */\r |
| 1183 | lastpgs = e->emasz % e->msegsz; /* #pgs in last MSEG */\r |
| 1184 | if (lastpgs==0) msnum--; /* adjust # of last MSEG */\r |
| 1185 | e->npgs = msnum==e->msegno ? lastpgs : e->msegsz; /* for last MSEG, only map available pgs */\r |
| 1186 | if (!cpu_ema_mmap01(e)) return FALSE; /* map npgs pages at ipgs */\r |
| 1187 | }\r |
| 1188 | BR = e->mseg + e->msoff; /* return address of element */\r |
| 1189 | return TRUE; /* and everything done */\r |
| 1190 | }\r |
| 1191 | \r |
| 1192 | /* .EMIO microcode routine, resolves element addr for EMA array\r |
| 1193 | * and maps the appropriate map segment\r |
| 1194 | * \r |
| 1195 | * Call:\r |
| 1196 | * OCT 105250B\r |
| 1197 | * DEF RTN error return (rtn), good return is rtn+1\r |
| 1198 | * DEF BUFLEN length of buffer in words (bufl)\r |
| 1199 | * DEF TABLE[,I] array declaration (dtbl)\r |
| 1200 | * DEF A(N)[,I] actual subscripts (atbl)\r |
| 1201 | * DEF A(N-1)[,I]\r |
| 1202 | * ...\r |
| 1203 | * DEF A(2)[,I]\r |
| 1204 | * DEF A(1)[,I]\r |
| 1205 | * RTN EQU * error return A="15", B="EM"\r |
| 1206 | * RTN+1 EQU *+1 good return B=logical address\r |
| 1207 | *\r |
| 1208 | * TABLE DEC # # dimensions\r |
| 1209 | * DEC -L(N)\r |
| 1210 | * DEC D(N-1)\r |
| 1211 | * DEC -L(N-1) lower bound (n-1)st dim\r |
| 1212 | * DEC D(N-2) (n-2)st dim \r |
| 1213 | * ...\r |
| 1214 | * DEC D(1) 1st dim\r |
| 1215 | * DEC -L(1) lower bound 1st dim\r |
| 1216 | * DEC # # words/element\r |
| 1217 | * OFFSET 1 EMA Low\r |
| 1218 | * OFFSET 2 EMA High\r |
| 1219 | */\r |
| 1220 | static t_stat cpu_ema_emio(uint32* rtn,uint32 bufl,uint32 dtbl,uint32 atbl,t_bool debug)\r |
| 1221 | {\r |
| 1222 | uint32 xidex, idext1;\r |
| 1223 | uint32 mseg, bufpgs, npgs;\r |
| 1224 | EMA4 ema4, *e = &ema4;\r |
| 1225 | \r |
| 1226 | xidex = ReadIO(idx,UMAP); /* read ID extension */\r |
| 1227 | if (bufl & SIGN || /* buffer length negative? */ \r |
| 1228 | xidex==0) goto em16; /* no EMA declared? */\r |
| 1229 | \r |
| 1230 | idext1 = ReadWA(xidex+1); /* |logstrt mseg|d|physstrt ema| */\r |
| 1231 | mseg = (idext1 >> 1) & MSEGMASK; /* get logical start MSEG */\r |
| 1232 | if (!cpu_ema_emas(dtbl,atbl,e)) goto em16; /* resolve address */\r |
| 1233 | bufpgs = (bufl + e->offs) >> 10; /* # of pgs reqd for buffer */\r |
| 1234 | if ((bufl + e->offs) & 01777) bufpgs++; /* S11 add 1 if not at pg boundary */\r |
| 1235 | if ((bufpgs + e->pgoff) > e->emasz) goto em16; /* exceeds EMA limit? */ \r |
| 1236 | npgs = (e->msoff + bufl) >> 10; /* # of pgs reqd for MSEG */\r |
| 1237 | if ((e->msoff + bufl) & 01777) npgs++; /* add 1 if not at pg boundary */\r |
| 1238 | if (npgs < e->msegsz) {\r |
| 1239 | e->mseg = mseg; /* logical stat of MSEG */\r |
| 1240 | if (!cpu_ema_emat(e)) goto em16; /* do a std mapping */\r |
| 1241 | } else {\r |
| 1242 | BR = mseg + e->offs; /* logical start of buffer */\r |
| 1243 | e->npgs = bufpgs; /* S5 # pgs required */\r |
| 1244 | e->ipgs = e->pgoff; /* S6 page offset to reqd pg */\r |
| 1245 | if (!cpu_ema_mmap02(e)) goto em16; /* do nonstd mapping */\r |
| 1246 | }\r |
| 1247 | (*rtn)++; /* return via good exit */ \r |
| 1248 | return SCPE_OK;\r |
| 1249 | \r |
| 1250 | em16: /* error condition */\r |
| 1251 | AR=0x3136; /* AR = '16' */ \r |
| 1252 | BR=0x454d; /* BR = 'EM' */\r |
| 1253 | return SCPE_OK; /* return via unmodified rtn */\r |
| 1254 | }\r |
| 1255 | \r |
| 1256 | /* .EMAP microcode routine, resolves both EMA/non-EMA calls\r |
| 1257 | * Call:\r |
| 1258 | * OCT 105257B\r |
| 1259 | * DEF RTN error return (rtn), good return is rtn+1\r |
| 1260 | * DEF ARRAY[,I] array base (abase)\r |
| 1261 | * DEF TABLE[,I] array declaration (dtbl)\r |
| 1262 | * DEF A(N)[,I] actual subscripts (atbl)\r |
| 1263 | * DEF A(N-1)[,I]\r |
| 1264 | * ...\r |
| 1265 | * DEF A(2)[,I]\r |
| 1266 | * DEF A(1)[,I]\r |
| 1267 | * RTN EQU * error return A="15", B="EM"\r |
| 1268 | * RTN+1 EQU *+1 good return B=logical address\r |
| 1269 | *\r |
| 1270 | * TABLE DEC # # dimensions\r |
| 1271 | * DEC -L(N)\r |
| 1272 | * DEC D(N-1)\r |
| 1273 | * DEC -L(N-1) lower bound (n-1)st dim\r |
| 1274 | * DEC D(N-2) (n-2)st dim \r |
| 1275 | * ...\r |
| 1276 | * DEC D(1) 1st dim\r |
| 1277 | * DEC -L(1) lower bound 1st dim\r |
| 1278 | * DEC # # words/element\r |
| 1279 | * OFFSET 1 EMA Low\r |
| 1280 | * OFFSET 2 EMA High\r |
| 1281 | */\r |
| 1282 | static t_stat cpu_ema_emap(uint32* rtn,uint32 abase,uint32 dtbl,uint32 atbl,t_bool debug)\r |
| 1283 | {\r |
| 1284 | uint32 xidex, eqt, idext0, idext1;\r |
| 1285 | int32 sub, act, low, ndim, sz;\r |
| 1286 | uint32 offs, pgoff, emasz, phys, msgn, mseg, sum, MA, pg0, pg1;\r |
| 1287 | \r |
| 1288 | xidex = ReadIO(idx,UMAP); /* read ID Extension */\r |
| 1289 | if (xidex) { /* is EMA declared? */\r |
| 1290 | idext1 = ReadWA(xidex+1); /* get word 1 of idext */\r |
| 1291 | mseg = (idext1 >> 1) & MSEGMASK; /* get logical start MSEG */\r |
| 1292 | if (abase >= mseg) { /* EMA reference? */\r |
| 1293 | if (!cpu_ema_resolve(dtbl,atbl,&sum)) /* calculate subscript */\r |
| 1294 | goto em15;\r |
| 1295 | offs = sum & 01777; /* address offset within page */\r |
| 1296 | pgoff = sum >> 10; /* ema offset in pages */\r |
| 1297 | if (pgoff > 1023) goto em15; /* overflow? */\r |
| 1298 | eqt = ReadIO(xeqt,UMAP);\r |
| 1299 | emasz = ReadWA(eqt+28) & 01777; /* EMA size in pages */\r |
| 1300 | phys = idext1 & 01777; /* physical start pg of EMA */ \r |
| 1301 | if (pgoff > emasz) goto em15; /* outside EMA range? */\r |
| 1302 | \r |
| 1303 | msgn = mseg >> 10; /* get # of 1st MSEG reg */\r |
| 1304 | phys += pgoff;\r |
| 1305 | \r |
| 1306 | pg0 = dms_rmap(UMAP+0); /* read base page map# */\r |
| 1307 | pg1 = dms_rmap(UMAP+1); /* save map# 1 */\r |
| 1308 | dms_wmap(UMAP+1,pg0); /* map #0 into reg #1 */\r |
| 1309 | \r |
| 1310 | WriteIO(umaps+msgn, phys, UMAP); /* store 1st mapped pg in user map */\r |
| 1311 | dms_wmap(UMAP+msgn, phys); /* and set the map register */\r |
| 1312 | phys = (pgoff+1)==emasz ? 0140000 : phys+1; /* protect 2nd map if end of EMA */\r |
| 1313 | WriteIO(umaps+msgn+1, phys, UMAP); /* store 2nd mapped pg in user map */\r |
| 1314 | dms_wmap(UMAP+msgn+1, phys); /* and set the map register */\r |
| 1315 | \r |
| 1316 | dms_wmap(UMAP+1,pg1); /* restore map #1 */\r |
| 1317 | \r |
| 1318 | idext0 = ReadWA(xidex+0) | 0100000; /* set NS flag in id extension */\r |
| 1319 | WriteIO(xidex+0, idext0, SMAP); /* save back value */\r |
| 1320 | AR = 0; /* was successful */\r |
| 1321 | BR = mseg + offs; /* calculate log address */ \r |
| 1322 | (*rtn)++; /* return via good exit */\r |
| 1323 | return SCPE_OK;\r |
| 1324 | }\r |
| 1325 | } /* not EMA reference */\r |
| 1326 | ndim = ReadW(dtbl++);\r |
| 1327 | Content-type: text/html
gitweb.hachti.de Git - simh.git/blame_incremental - HP2100/hp2100_cpu5.c
500 - Internal Server Error
Malformed UTF-8 character (fatal) at (eval 5) line 1, <$fd> line 1327.