| 1 | /* vax_mmu.c - VAX memory management\r |
| 2 | \r |
| 3 | Copyright (c) 1998-2008, Robert M Supnik\r |
| 4 | \r |
| 5 | Permission is hereby granted, free of charge, to any person obtaining a\r |
| 6 | copy of this software and associated documentation files (the "Software"),\r |
| 7 | to deal in the Software without restriction, including without limitation\r |
| 8 | the rights to use, copy, modify, merge, publish, distribute, sublicense,\r |
| 9 | and/or sell copies of the Software, and to permit persons to whom the\r |
| 10 | Software is furnished to do so, subject to the following conditions:\r |
| 11 | \r |
| 12 | The above copyright notice and this permission notice shall be included in\r |
| 13 | all copies or substantial portions of the Software.\r |
| 14 | \r |
| 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r |
| 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r |
| 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\r |
| 18 | ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r |
| 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r |
| 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r |
| 21 | \r |
| 22 | Except as contained in this notice, the name of Robert M Supnik shall not be\r |
| 23 | used in advertising or otherwise to promote the sale, use or other dealings\r |
| 24 | in this Software without prior written authorization from Robert M Supnik.\r |
| 25 | \r |
| 26 | 28-May-08 RMS Inlined physical memory routines\r |
| 27 | 29-Apr-07 RMS Added address masking for system page table reads\r |
| 28 | 22-Sep-05 RMS Fixed declarations (from Sterling Garwood)\r |
| 29 | 30-Sep-04 RMS Comment and formating changes\r |
| 30 | 19-Sep-03 RMS Fixed upper/lower case linkage problems on VMS\r |
| 31 | 01-Jun-03 RMS Fixed compilation problem with USE_ADDR64\r |
| 32 | \r |
| 33 | This module contains the instruction simulators for\r |
| 34 | \r |
| 35 | Read - read virtual\r |
| 36 | Write - write virtual\r |
| 37 | ReadL(P) - read aligned physical longword (physical context)\r |
| 38 | WriteL(P) - write aligned physical longword (physical context)\r |
| 39 | ReadB(W) - read aligned physical byte (word)\r |
| 40 | WriteB(W) - write aligned physical byte (word)\r |
| 41 | Test - test acccess\r |
| 42 | \r |
| 43 | zap_tb - clear TB\r |
| 44 | zap_tb_ent - clear TB entry\r |
| 45 | chk_tb_ent - check TB entry\r |
| 46 | set_map_reg - set up working map registers\r |
| 47 | */\r |
| 48 | \r |
| 49 | #include "vax_defs.h"\r |
| 50 | #include <setjmp.h>\r |
| 51 | \r |
| 52 | typedef struct {\r |
| 53 | int32 tag; /* tag */\r |
| 54 | int32 pte; /* pte */\r |
| 55 | } TLBENT;\r |
| 56 | \r |
| 57 | extern uint32 *M;\r |
| 58 | extern const uint32 align[4];\r |
| 59 | extern int32 PSL;\r |
| 60 | extern int32 mapen;\r |
| 61 | extern int32 p1, p2;\r |
| 62 | extern int32 P0BR, P0LR;\r |
| 63 | extern int32 P1BR, P1LR;\r |
| 64 | extern int32 SBR, SLR;\r |
| 65 | extern int32 SISR;\r |
| 66 | extern jmp_buf save_env;\r |
| 67 | extern UNIT cpu_unit;\r |
| 68 | \r |
| 69 | int32 d_p0br, d_p0lr; /* dynamic copies */\r |
| 70 | int32 d_p1br, d_p1lr; /* altered per ucode */\r |
| 71 | int32 d_sbr, d_slr;\r |
| 72 | extern int32 mchk_va, mchk_ref; /* for mcheck */\r |
| 73 | TLBENT stlb[VA_TBSIZE], ptlb[VA_TBSIZE];\r |
| 74 | static const int32 insert[4] = {\r |
| 75 | 0x00000000, 0x000000FF, 0x0000FFFF, 0x00FFFFFF\r |
| 76 | };\r |
| 77 | static const int32 cvtacc[16] = { 0, 0,\r |
| 78 | TLB_ACCW (KERN)+TLB_ACCR (KERN),\r |
| 79 | TLB_ACCR (KERN),\r |
| 80 | TLB_ACCW (KERN)+TLB_ACCW (EXEC)+TLB_ACCW (SUPV)+TLB_ACCW (USER)+\r |
| 81 | TLB_ACCR (KERN)+TLB_ACCR (EXEC)+TLB_ACCR (SUPV)+TLB_ACCR (USER),\r |
| 82 | TLB_ACCW (KERN)+TLB_ACCW (EXEC)+TLB_ACCR (KERN)+TLB_ACCR (EXEC),\r |
| 83 | TLB_ACCW (KERN)+TLB_ACCR (KERN)+TLB_ACCR (EXEC),\r |
| 84 | TLB_ACCR (KERN)+TLB_ACCR (EXEC),\r |
| 85 | TLB_ACCW (KERN)+TLB_ACCW (EXEC)+TLB_ACCW (SUPV)+\r |
| 86 | TLB_ACCR (KERN)+TLB_ACCR (EXEC)+TLB_ACCR (SUPV),\r |
| 87 | TLB_ACCW (KERN)+TLB_ACCW (EXEC)+\r |
| 88 | TLB_ACCR (KERN)+TLB_ACCR (EXEC)+TLB_ACCR (SUPV),\r |
| 89 | TLB_ACCW (KERN)+TLB_ACCR (KERN)+TLB_ACCR (EXEC)+TLB_ACCR (SUPV),\r |
| 90 | TLB_ACCR (KERN)+TLB_ACCR (EXEC)+TLB_ACCR (SUPV),\r |
| 91 | TLB_ACCW (KERN)+TLB_ACCW (EXEC)+TLB_ACCW (SUPV)+\r |
| 92 | TLB_ACCR (KERN)+TLB_ACCR (EXEC)+TLB_ACCR (SUPV)+TLB_ACCR (USER),\r |
| 93 | TLB_ACCW (KERN)+TLB_ACCW (EXEC)+\r |
| 94 | TLB_ACCR (KERN)+TLB_ACCR (EXEC)+TLB_ACCR (SUPV)+TLB_ACCR (USER),\r |
| 95 | TLB_ACCW (KERN)+\r |
| 96 | TLB_ACCR (KERN)+TLB_ACCR (EXEC)+TLB_ACCR (SUPV)+TLB_ACCR (USER),\r |
| 97 | TLB_ACCR (KERN)+TLB_ACCR (EXEC)+TLB_ACCR (SUPV)+TLB_ACCR (USER)\r |
| 98 | };\r |
| 99 | \r |
| 100 | t_stat tlb_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);\r |
| 101 | t_stat tlb_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);\r |
| 102 | t_stat tlb_reset (DEVICE *dptr);\r |
| 103 | \r |
| 104 | TLBENT fill (uint32 va, int32 lnt, int32 acc, int32 *stat);\r |
| 105 | extern int32 ReadIO (uint32 pa, int32 lnt);\r |
| 106 | extern void WriteIO (uint32 pa, int32 val, int32 lnt);\r |
| 107 | extern int32 ReadReg (uint32 pa, int32 lnt);\r |
| 108 | extern void WriteReg (uint32 pa, int32 val, int32 lnt);\r |
| 109 | \r |
| 110 | /* TLB data structures\r |
| 111 | \r |
| 112 | tlb_dev pager device descriptor\r |
| 113 | tlb_unit pager units\r |
| 114 | pager_reg pager register list\r |
| 115 | */\r |
| 116 | \r |
| 117 | UNIT tlb_unit[] = {\r |
| 118 | { UDATA (NULL, UNIT_FIX, VA_TBSIZE * 2) },\r |
| 119 | { UDATA (NULL, UNIT_FIX, VA_TBSIZE * 2) }\r |
| 120 | };\r |
| 121 | \r |
| 122 | REG tlb_reg[] = {\r |
| 123 | { NULL }\r |
| 124 | };\r |
| 125 | \r |
| 126 | DEVICE tlb_dev = {\r |
| 127 | "TLB", tlb_unit, tlb_reg, NULL,\r |
| 128 | 2, 16, VA_N_TBI * 2, 1, 16, 32,\r |
| 129 | &tlb_ex, &tlb_dep, &tlb_reset,\r |
| 130 | NULL, NULL, NULL\r |
| 131 | };\r |
| 132 | \r |
| 133 | /* Read and write virtual\r |
| 134 | \r |
| 135 | These routines logically fall into three phases:\r |
| 136 | \r |
| 137 | 1. Look up the virtual address in the translation buffer, calling\r |
| 138 | the fill routine on a tag mismatch or access mismatch (invalid\r |
| 139 | tlb entries have access = 0 and thus always mismatch). The\r |
| 140 | fill routine handles all errors. If the resulting physical\r |
| 141 | address is aligned, do an aligned physical read or write.\r |
| 142 | 2. Test for unaligned across page boundaries. If cross page, look\r |
| 143 | up the physical address of the second page. If not cross page,\r |
| 144 | the second physical address is the same as the first.\r |
| 145 | 3. Using the two physical addresses, do an unaligned read or\r |
| 146 | write, with three cases: unaligned long, unaligned word within\r |
| 147 | a longword, unaligned word crossing a longword boundary.\r |
| 148 | \r |
| 149 | Note that these routines do not handle quad or octa references.\r |
| 150 | */\r |
| 151 | \r |
| 152 | /* Read virtual\r |
| 153 | \r |
| 154 | Inputs:\r |
| 155 | va = virtual address\r |
| 156 | lnt = length code (BWL)\r |
| 157 | acc = access code (KESU)\r |
| 158 | Output:\r |
| 159 | returned data, right justified in 32b longword\r |
| 160 | */\r |
| 161 | \r |
| 162 | int32 Read (uint32 va, int32 lnt, int32 acc)\r |
| 163 | {\r |
| 164 | int32 vpn, off, tbi, pa;\r |
| 165 | int32 pa1, bo, sc, wl, wh;\r |
| 166 | TLBENT xpte;\r |
| 167 | \r |
| 168 | mchk_va = va;\r |
| 169 | if (mapen) { /* mapping on? */\r |
| 170 | vpn = VA_GETVPN (va); /* get vpn, offset */\r |
| 171 | off = VA_GETOFF (va);\r |
| 172 | tbi = VA_GETTBI (vpn);\r |
| 173 | xpte = (va & VA_S0)? stlb[tbi]: ptlb[tbi]; /* access tlb */\r |
| 174 | if (((xpte.pte & acc) == 0) || (xpte.tag != vpn) ||\r |
| 175 | ((acc & TLB_WACC) && ((xpte.pte & TLB_M) == 0)))\r |
| 176 | xpte = fill (va, lnt, acc, NULL); /* fill if needed */\r |
| 177 | pa = (xpte.pte & TLB_PFN) | off; /* get phys addr */\r |
| 178 | }\r |
| 179 | else pa = va & PAMASK;\r |
| 180 | if ((pa & (lnt - 1)) == 0) { /* aligned? */\r |
| 181 | if (lnt >= L_LONG) return ReadL (pa); /* long, quad? */\r |
| 182 | if (lnt == L_WORD) return ReadW (pa); /* word? */\r |
| 183 | return ReadB (pa); /* byte */\r |
| 184 | }\r |
| 185 | if (mapen && ((off + lnt) > VA_PAGSIZE)) { /* cross page? */\r |
| 186 | vpn = VA_GETVPN (va + lnt); /* vpn 2nd page */\r |
| 187 | tbi = VA_GETTBI (vpn);\r |
| 188 | xpte = (va & VA_S0)? stlb[tbi]: ptlb[tbi]; /* access tlb */\r |
| 189 | if (((xpte.pte & acc) == 0) || (xpte.tag != vpn) ||\r |
| 190 | ((acc & TLB_WACC) && ((xpte.pte & TLB_M) == 0)))\r |
| 191 | xpte = fill (va + lnt, lnt, acc, NULL); /* fill if needed */\r |
| 192 | pa1 = (xpte.pte & TLB_PFN) | VA_GETOFF (va + 4);\r |
| 193 | }\r |
| 194 | else pa1 = (pa + 4) & PAMASK; /* not cross page */\r |
| 195 | bo = pa & 3;\r |
| 196 | if (lnt >= L_LONG) { /* lw unaligned? */\r |
| 197 | sc = bo << 3;\r |
| 198 | wl = ReadL (pa); /* read both lw */\r |
| 199 | wh = ReadL (pa1); /* extract */\r |
| 200 | return ((((wl >> sc) & align[bo]) | (wh << (32 - sc))) & LMASK);\r |
| 201 | }\r |
| 202 | else if (bo == 1) return ((ReadL (pa) >> 8) & WMASK);\r |
| 203 | else {\r |
| 204 | wl = ReadL (pa); /* word cross lw */\r |
| 205 | wh = ReadL (pa1); /* read, extract */\r |
| 206 | return (((wl >> 24) & 0xFF) | ((wh & 0xFF) << 8));\r |
| 207 | }\r |
| 208 | }\r |
| 209 | \r |
| 210 | /* Write virtual\r |
| 211 | \r |
| 212 | Inputs:\r |
| 213 | va = virtual address\r |
| 214 | val = data to be written, right justified in 32b lw\r |
| 215 | lnt = length code (BWL)\r |
| 216 | acc = access code (KESU)\r |
| 217 | Output:\r |
| 218 | none\r |
| 219 | */\r |
| 220 | \r |
| 221 | void Write (uint32 va, int32 val, int32 lnt, int32 acc)\r |
| 222 | {\r |
| 223 | int32 vpn, off, tbi, pa;\r |
| 224 | int32 pa1, bo, sc, wl, wh;\r |
| 225 | TLBENT xpte;\r |
| 226 | \r |
| 227 | mchk_va = va;\r |
| 228 | if (mapen) {\r |
| 229 | vpn = VA_GETVPN (va);\r |
| 230 | off = VA_GETOFF (va);\r |
| 231 | tbi = VA_GETTBI (vpn);\r |
| 232 | xpte = (va & VA_S0)? stlb[tbi]: ptlb[tbi]; /* access tlb */\r |
| 233 | if (((xpte.pte & acc) == 0) || (xpte.tag != vpn) ||\r |
| 234 | ((xpte.pte & TLB_M) == 0))\r |
| 235 | xpte = fill (va, lnt, acc, NULL);\r |
| 236 | pa = (xpte.pte & TLB_PFN) | off;\r |
| 237 | }\r |
| 238 | else pa = va & PAMASK;\r |
| 239 | if ((pa & (lnt - 1)) == 0) { /* aligned? */\r |
| 240 | if (lnt >= L_LONG) WriteL (pa, val); /* long, quad? */\r |
| 241 | else if (lnt == L_WORD) WriteW (pa, val); /* word? */\r |
| 242 | else WriteB (pa, val); /* byte */\r |
| 243 | return;\r |
| 244 | }\r |
| 245 | if (mapen && ((off + lnt) > VA_PAGSIZE)) {\r |
| 246 | vpn = VA_GETVPN (va + 4);\r |
| 247 | tbi = VA_GETTBI (vpn);\r |
| 248 | xpte = (va & VA_S0)? stlb[tbi]: ptlb[tbi]; /* access tlb */\r |
| 249 | if (((xpte.pte & acc) == 0) || (xpte.tag != vpn) ||\r |
| 250 | ((xpte.pte & TLB_M) == 0))\r |
| 251 | xpte = fill (va + lnt, lnt, acc, NULL);\r |
| 252 | pa1 = (xpte.pte & TLB_PFN) | VA_GETOFF (va + 4);\r |
| 253 | }\r |
| 254 | else pa1 = (pa + 4) & PAMASK;\r |
| 255 | bo = pa & 3;\r |
| 256 | wl = ReadL (pa);\r |
| 257 | if (lnt >= L_LONG) {\r |
| 258 | sc = bo << 3;\r |
| 259 | wh = ReadL (pa1);\r |
| 260 | wl = (wl & insert[bo]) | ((val << sc) & LMASK);\r |
| 261 | wh = (wh & ~insert[bo]) | ((val >> (32 - sc)) & insert[bo]);\r |
| 262 | WriteL (pa, wl);\r |
| 263 | WriteL (pa1, wh);\r |
| 264 | }\r |
| 265 | else if (bo == 1) {\r |
| 266 | wl = (wl & 0xFF0000FF) | (val << 8);\r |
| 267 | WriteL (pa, wl);\r |
| 268 | }\r |
| 269 | else {\r |
| 270 | wh = ReadL (pa1);\r |
| 271 | wl = (wl & 0x00FFFFFF) | ((val & 0xFF) << 24);\r |
| 272 | wh = (wh & 0xFFFFFF00) | ((val >> 8) & 0xFF);\r |
| 273 | WriteL (pa, wl);\r |
| 274 | WriteL (pa1, wh);\r |
| 275 | }\r |
| 276 | return;\r |
| 277 | }\r |
| 278 | \r |
| 279 | /* Test access to a byte (VAX PROBEx) */\r |
| 280 | \r |
| 281 | int32 Test (uint32 va, int32 acc, int32 *status)\r |
| 282 | {\r |
| 283 | int32 vpn, off, tbi;\r |
| 284 | TLBENT xpte;\r |
| 285 | \r |
| 286 | *status = PR_OK; /* assume ok */\r |
| 287 | if (mapen) { /* mapping on? */\r |
| 288 | vpn = VA_GETVPN (va); /* get vpn, off */\r |
| 289 | off = VA_GETOFF (va);\r |
| 290 | tbi = VA_GETTBI (vpn);\r |
| 291 | xpte = (va & VA_S0)? stlb[tbi]: ptlb[tbi]; /* access tlb */\r |
| 292 | if ((xpte.pte & acc) && (xpte.tag == vpn)) /* TB hit, acc ok? */ \r |
| 293 | return (xpte.pte & TLB_PFN) | off;\r |
| 294 | xpte = fill (va, L_BYTE, acc, status); /* fill TB */\r |
| 295 | if (*status == PR_OK) return (xpte.pte & TLB_PFN) | off;\r |
| 296 | else return -1;\r |
| 297 | }\r |
| 298 | return va & PAMASK; /* ret phys addr */\r |
| 299 | }\r |
| 300 | \r |
| 301 | /* Read aligned physical (in virtual context, unless indicated)\r |
| 302 | \r |
| 303 | Inputs:\r |
| 304 | pa = physical address, naturally aligned\r |
| 305 | Output:\r |
| 306 | returned data, right justified in 32b longword\r |
| 307 | */\r |
| 308 | \r |
| 309 | SIM_INLINE int32 ReadB (uint32 pa)\r |
| 310 | {\r |
| 311 | int32 dat;\r |
| 312 | \r |
| 313 | if (ADDR_IS_MEM (pa)) dat = M[pa >> 2];\r |
| 314 | else {\r |
| 315 | mchk_ref = REF_V;\r |
| 316 | if (ADDR_IS_IO (pa)) dat = ReadIO (pa, L_BYTE);\r |
| 317 | else dat = ReadReg (pa, L_BYTE);\r |
| 318 | }\r |
| 319 | return ((dat >> ((pa & 3) << 3)) & BMASK);\r |
| 320 | }\r |
| 321 | \r |
| 322 | SIM_INLINE int32 ReadW (uint32 pa)\r |
| 323 | {\r |
| 324 | int32 dat;\r |
| 325 | \r |
| 326 | if (ADDR_IS_MEM (pa)) dat = M[pa >> 2];\r |
| 327 | else {\r |
| 328 | mchk_ref = REF_V;\r |
| 329 | if (ADDR_IS_IO (pa)) dat = ReadIO (pa, L_WORD);\r |
| 330 | else dat = ReadReg (pa, L_WORD);\r |
| 331 | }\r |
| 332 | return ((dat >> ((pa & 2)? 16: 0)) & WMASK);\r |
| 333 | }\r |
| 334 | \r |
| 335 | SIM_INLINE int32 ReadL (uint32 pa)\r |
| 336 | {\r |
| 337 | if (ADDR_IS_MEM (pa)) return M[pa >> 2];\r |
| 338 | mchk_ref = REF_V;\r |
| 339 | if (ADDR_IS_IO (pa)) return ReadIO (pa, L_LONG);\r |
| 340 | return ReadReg (pa, L_LONG);\r |
| 341 | }\r |
| 342 | \r |
| 343 | SIM_INLINE int32 ReadLP (uint32 pa)\r |
| 344 | {\r |
| 345 | if (ADDR_IS_MEM (pa)) return M[pa >> 2];\r |
| 346 | mchk_va = pa;\r |
| 347 | mchk_ref = REF_P;\r |
| 348 | if (ADDR_IS_IO (pa)) return ReadIO (pa, L_LONG);\r |
| 349 | return ReadReg (pa, L_LONG);\r |
| 350 | }\r |
| 351 | \r |
| 352 | /* Write aligned physical (in virtual context, unless indicated)\r |
| 353 | \r |
| 354 | Inputs:\r |
| 355 | pa = physical address, naturally aligned\r |
| 356 | val = data to be written, right justified in 32b longword\r |
| 357 | Output:\r |
| 358 | none\r |
| 359 | */\r |
| 360 | \r |
| 361 | SIM_INLINE void WriteB (uint32 pa, int32 val)\r |
| 362 | {\r |
| 363 | if (ADDR_IS_MEM (pa)) {\r |
| 364 | int32 id = pa >> 2;\r |
| 365 | int32 sc = (pa & 3) << 3;\r |
| 366 | int32 mask = 0xFF << sc;\r |
| 367 | M[id] = (M[id] & ~mask) | (val << sc);\r |
| 368 | }\r |
| 369 | else {\r |
| 370 | mchk_ref = REF_V;\r |
| 371 | if (ADDR_IS_IO (pa)) WriteIO (pa, val, L_BYTE);\r |
| 372 | else WriteReg (pa, val, L_BYTE);\r |
| 373 | }\r |
| 374 | return;\r |
| 375 | }\r |
| 376 | \r |
| 377 | SIM_INLINE void WriteW (uint32 pa, int32 val)\r |
| 378 | {\r |
| 379 | if (ADDR_IS_MEM (pa)) {\r |
| 380 | int32 id = pa >> 2;\r |
| 381 | M[id] = (pa & 2)? (M[id] & 0xFFFF) | (val << 16):\r |
| 382 | (M[id] & ~0xFFFF) | val;\r |
| 383 | }\r |
| 384 | else {\r |
| 385 | mchk_ref = REF_V;\r |
| 386 | if (ADDR_IS_IO (pa)) WriteIO (pa, val, L_WORD);\r |
| 387 | else WriteReg (pa, val, L_WORD);\r |
| 388 | }\r |
| 389 | return;\r |
| 390 | }\r |
| 391 | \r |
| 392 | SIM_INLINE void WriteL (uint32 pa, int32 val)\r |
| 393 | {\r |
| 394 | if (ADDR_IS_MEM (pa)) M[pa >> 2] = val;\r |
| 395 | else {\r |
| 396 | mchk_ref = REF_V;\r |
| 397 | if (ADDR_IS_IO (pa)) WriteIO (pa, val, L_LONG);\r |
| 398 | else WriteReg (pa, val, L_LONG);\r |
| 399 | }\r |
| 400 | return;\r |
| 401 | }\r |
| 402 | \r |
| 403 | void WriteLP (uint32 pa, int32 val)\r |
| 404 | {\r |
| 405 | if (ADDR_IS_MEM (pa)) M[pa >> 2] = val;\r |
| 406 | else {\r |
| 407 | mchk_va = pa;\r |
| 408 | mchk_ref = REF_P;\r |
| 409 | if (ADDR_IS_IO (pa)) WriteIO (pa, val, L_LONG);\r |
| 410 | else WriteReg (pa, val, L_LONG);\r |
| 411 | }\r |
| 412 | return;\r |
| 413 | }\r |
| 414 | \r |
| 415 | /* TLB fill\r |
| 416 | \r |
| 417 | This routine fills the TLB after a tag or access mismatch, or\r |
| 418 | on a write if pte<m> = 0. It fills the TLB and returns the\r |
| 419 | pte to the caller. On an error, it aborts directly to the\r |
| 420 | fault handler in the CPU.\r |
| 421 | \r |
| 422 | If called from map (VAX PROBEx), the error status is returned\r |
| 423 | to the caller, and no fault occurs.\r |
| 424 | */\r |
| 425 | \r |
| 426 | #define MM_ERR(param) { \\r |
| 427 | if (stat) { *stat = param; return zero_pte; } \\r |
| 428 | p1 = MM_PARAM (acc & TLB_WACC, param); \\r |
| 429 | p2 = va; \\r |
| 430 | ABORT ((param & PR_TNV)? ABORT_TNV: ABORT_ACV); }\r |
| 431 | \r |
| 432 | TLBENT fill (uint32 va, int32 lnt, int32 acc, int32 *stat)\r |
| 433 | {\r |
| 434 | int32 ptidx = (((uint32) va) >> 7) & ~03;\r |
| 435 | int32 tlbpte, ptead, pte, tbi, vpn;\r |
| 436 | static TLBENT zero_pte = { 0, 0 };\r |
| 437 | \r |
| 438 | if (va & VA_S0) { /* system space? */\r |
| 439 | if (ptidx >= d_slr) /* system */\r |
| 440 | MM_ERR (PR_LNV);\r |
| 441 | ptead = (d_sbr + ptidx) & PAMASK;\r |
| 442 | }\r |
| 443 | else {\r |
| 444 | if (va & VA_P1) { /* P1? */\r |
| 445 | if (ptidx < d_p1lr) MM_ERR (PR_LNV);\r |
| 446 | ptead = d_p1br + ptidx;\r |
| 447 | }\r |
| 448 | else { /* P0 */\r |
| 449 | if (ptidx >= d_p0lr) MM_ERR (PR_LNV);\r |
| 450 | ptead = d_p0br + ptidx;\r |
| 451 | }\r |
| 452 | if ((ptead & VA_S0) == 0)\r |
| 453 | ABORT (STOP_PPTE); /* ppte must be sys */\r |
| 454 | vpn = VA_GETVPN (ptead); /* get vpn, tbi */\r |
| 455 | tbi = VA_GETTBI (vpn);\r |
| 456 | if (stlb[tbi].tag != vpn) { /* in sys tlb? */\r |
| 457 | ptidx = ((uint32) ptead) >> 7; /* xlate like sys */\r |
| 458 | if (ptidx >= d_slr)\r |
| 459 | MM_ERR (PR_PLNV);\r |
| 460 | pte = ReadLP ((d_sbr + ptidx) & PAMASK); /* get system pte */\r |
| 461 | #if defined (VAX_780)\r |
| 462 | if ((pte & PTE_ACC) == 0) MM_ERR (PR_PACV); /* spte ACV? */\r |
| 463 | #endif\r |
| 464 | if ((pte & PTE_V) == 0) MM_ERR (PR_PTNV); /* spte TNV? */\r |
| 465 | stlb[tbi].tag = vpn; /* set stlb tag */\r |
| 466 | stlb[tbi].pte = cvtacc[PTE_GETACC (pte)] |\r |
| 467 | ((pte << VA_N_OFF) & TLB_PFN); /* set stlb data */\r |
| 468 | }\r |
| 469 | ptead = (stlb[tbi].pte & TLB_PFN) | VA_GETOFF (ptead);\r |
| 470 | }\r |
| 471 | pte = ReadL (ptead); /* read pte */\r |
| 472 | tlbpte = cvtacc[PTE_GETACC (pte)] | /* cvt access */\r |
| 473 | ((pte << VA_N_OFF) & TLB_PFN); /* set addr */\r |
| 474 | if ((tlbpte & acc) == 0) MM_ERR (PR_ACV); /* chk access */\r |
| 475 | if ((pte & PTE_V) == 0) MM_ERR (PR_TNV); /* check valid */\r |
| 476 | if (acc & TLB_WACC) { /* write? */\r |
| 477 | if ((pte & PTE_M) == 0) WriteL (ptead, pte | PTE_M);\r |
| 478 | tlbpte = tlbpte | TLB_M; /* set M */\r |
| 479 | }\r |
| 480 | vpn = VA_GETVPN (va);\r |
| 481 | tbi = VA_GETTBI (vpn);\r |
| 482 | if ((va & VA_S0) == 0) { /* process space? */\r |
| 483 | ptlb[tbi].tag = vpn; /* store tlb ent */\r |
| 484 | ptlb[tbi].pte = tlbpte;\r |
| 485 | return ptlb[tbi];\r |
| 486 | }\r |
| 487 | stlb[tbi].tag = vpn; /* system space */\r |
| 488 | stlb[tbi].pte = tlbpte; /* store tlb ent */\r |
| 489 | return stlb[tbi];\r |
| 490 | }\r |
| 491 | \r |
| 492 | /* Utility routines */\r |
| 493 | \r |
| 494 | extern void set_map_reg (void)\r |
| 495 | {\r |
| 496 | d_p0br = P0BR & ~03;\r |
| 497 | d_p1br = (P1BR - 0x800000) & ~03; /* VA<30> >> 7 */\r |
| 498 | d_sbr = (SBR - 0x1000000) & ~03; /* VA<31> >> 7 */\r |
| 499 | d_p0lr = (P0LR << 2);\r |
| 500 | d_p1lr = (P1LR << 2) + 0x800000; /* VA<30> >> 7 */\r |
| 501 | d_slr = (SLR << 2) + 0x1000000; /* VA<31> >> 7 */\r |
| 502 | return;\r |
| 503 | }\r |
| 504 | \r |
| 505 | /* Zap process (0) or whole (1) tb */\r |
| 506 | \r |
| 507 | void zap_tb (int stb)\r |
| 508 | {\r |
| 509 | int32 i;\r |
| 510 | \r |
| 511 | for (i = 0; i < VA_TBSIZE; i++) {\r |
| 512 | ptlb[i].tag = ptlb[i].pte = -1;\r |
| 513 | if (stb) stlb[i].tag = stlb[i].pte = -1;\r |
| 514 | }\r |
| 515 | return;\r |
| 516 | }\r |
| 517 | \r |
| 518 | /* Zap single tb entry corresponding to va */\r |
| 519 | \r |
| 520 | void zap_tb_ent (uint32 va)\r |
| 521 | {\r |
| 522 | int32 tbi = VA_GETTBI (VA_GETVPN (va));\r |
| 523 | \r |
| 524 | if (va & VA_S0) stlb[tbi].tag = stlb[tbi].pte = -1;\r |
| 525 | else ptlb[tbi].tag = ptlb[tbi].pte = -1;\r |
| 526 | return;\r |
| 527 | }\r |
| 528 | \r |
| 529 | /* Check for tlb entry corresponding to va */\r |
| 530 | \r |
| 531 | t_bool chk_tb_ent (uint32 va)\r |
| 532 | {\r |
| 533 | int32 vpn = VA_GETVPN (va);\r |
| 534 | int32 tbi = VA_GETTBI (vpn);\r |
| 535 | TLBENT xpte;\r |
| 536 | \r |
| 537 | xpte = (va & VA_S0)? stlb[tbi]: ptlb[tbi];\r |
| 538 | if (xpte.tag == vpn) return TRUE;\r |
| 539 | return FALSE;\r |
| 540 | }\r |
| 541 | \r |
| 542 | /* TLB examine */\r |
| 543 | \r |
| 544 | t_stat tlb_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)\r |
| 545 | {\r |
| 546 | int32 tlbn = uptr - tlb_unit;\r |
| 547 | int32 idx = (uint32) addr >> 1;\r |
| 548 | \r |
| 549 | if (idx >= VA_TBSIZE) return SCPE_NXM;\r |
| 550 | if (addr & 1) *vptr = ((uint32) (tlbn? stlb[idx].pte: ptlb[idx].pte));\r |
| 551 | else *vptr = ((uint32) (tlbn? stlb[idx].tag: ptlb[idx].tag));\r |
| 552 | return SCPE_OK;\r |
| 553 | }\r |
| 554 | \r |
| 555 | /* TLB deposit */\r |
| 556 | \r |
| 557 | t_stat tlb_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)\r |
| 558 | {\r |
| 559 | int32 tlbn = uptr - tlb_unit;\r |
| 560 | int32 idx = (uint32) addr >> 1;\r |
| 561 | \r |
| 562 | if (idx >= VA_TBSIZE) return SCPE_NXM;\r |
| 563 | if (addr & 1) {\r |
| 564 | if (tlbn) stlb[idx].pte = (int32) val;\r |
| 565 | else ptlb[idx].pte = (int32) val;\r |
| 566 | }\r |
| 567 | else {\r |
| 568 | if (tlbn) stlb[idx].tag = (int32) val;\r |
| 569 | else ptlb[idx].tag = (int32) val;\r |
| 570 | }\r |
| 571 | return SCPE_OK;\r |
| 572 | }\r |
| 573 | \r |
| 574 | /* TLB reset */\r |
| 575 | \r |
| 576 | t_stat tlb_reset (DEVICE *dptr)\r |
| 577 | {\r |
| 578 | int32 i;\r |
| 579 | \r |
| 580 | for (i = 0; i < VA_TBSIZE; i++)\r |
| 581 | stlb[i].tag = ptlb[i].tag = stlb[i].pte = ptlb[i].pte = -1;\r |
| 582 | return SCPE_OK;\r |
| 583 | }\r |