First Commit of my working state
[simh.git] / PDP10 / pdp10_pag.c
CommitLineData
196ba1fc
PH
1/* pdp10_pag.c: PDP-10 paging subsystem simulator\r
2\r
3 Copyright (c) 1993-2005, 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 pag KS10 pager\r
27\r
28 22-Sep-05 RMS Fixed declarations (from Sterling Garwood)\r
29 02-Dec-01 RMS Fixed bug in ITS LPMR (found by Dave Conroy)\r
30 21-Aug-01 RMS Fixed bug in ITS paging (found by Miriam Lennox)\r
31 Removed register from declarations\r
32 19-May-01 RMS Added workaround for TOPS-20 V4.1 boot bug\r
33 03-May-01 RMS Fixed bug in indirect page table pointer processing\r
34 29-Apr-01 RMS Added CLRCSH for ITS, fixed LPMR\r
35\r
36 The pager consists of a standard hardware part (the translation\r
37 tables) and an operating-system specific page table fill routine.\r
38\r
39 There are two translation tables, one for executive mode and one\r
40 for user mode. Each table consists of 512 page table entries,\r
41 one for each page in the 18b virtual address space. Each pte\r
42 contains (in the hardware) a valid bit, a writeable bit, an\r
43 address space bit (executive or user), and a cacheable bit, plus\r
44 the physical page number corresponding to the virtual page. In\r
45 the simulator, the pte is expanded for rapid processing of normal\r
46 reads and writes. An expanded pte contains a valid bit, a writeable\r
47 bit, and the physical page number shifted left by the page size.\r
48\r
49 Expanded pte meaning\r
50 0 invalid\r
51 >0 read only\r
52 <0 read write\r
53\r
54 There is a third, physical table, which is used in place of the\r
55 executive and user tables if paging is off. Its entries are always\r
56 valid and always writeable.\r
57\r
58 To translate a virtual to physical address, the simulator uses\r
59 the virtual page number to index into the appropriate page table.\r
60 If the page table entry (pte) is not valid, the page fill routine\r
61 is called to see if the entry is merely not filled or is truly\r
62 inaccessible. If the pte is valid but not writeable, and the\r
63 reference is a write reference, the page fill routine is also\r
64 called to see if the reference can be resolved.\r
65\r
66 The page fill routine is operating system dependent. Three styles\r
67 of paging are supported:\r
68\r
69 TOPS10 known in the KS10 microcode as KI10 paging,\r
70 used by earlier versions of TOPS10\r
71 TOPS20 known in the KS10 microcode as KL10 paging,\r
72 used by later versions of TOPS10, and TOPS20\r
73 ITS used only by ITS\r
74\r
75 TOPS10 vs TOPS20 is selected by a bit in the EBR; ITS paging is\r
76 "hardwired" (it required different microcode).\r
77*/\r
78\r
79#include "pdp10_defs.h"\r
80#include <setjmp.h>\r
81\r
82/* Page table (contains expanded pte's) */\r
83\r
84#define PTBL_ASIZE PAG_N_VPN\r
85#define PTBL_MEMSIZE (1 << PTBL_ASIZE) /* page table size */\r
86#define PTBL_AMASK (PTBL_MEMSIZE - 1)\r
87#define PTBL_M (1u << 31) /* must be sign bit */\r
88#define PTBL_V (1u << 30)\r
89#define PTBL_MASK (PAG_PPN | PTBL_M | PTBL_V)\r
90\r
91/* NXM processing */\r
92\r
93#define REF_V 0 /* ref is virt */\r
94#define REF_P 1 /* ref is phys */\r
95#define PF_OK 0 /* pfail ok */\r
96#define PF_TR 1 /* pfail trap */\r
97\r
98extern d10 *M;\r
99extern d10 acs[AC_NBLK * AC_NUM];\r
100extern d10 *ac_cur, *ac_prv, *last_pa;\r
101extern a10 epta, upta;\r
102extern int32 flags;\r
103extern d10 pager_word;\r
104extern int32 apr_flg;\r
105extern d10 ebr, ubr, hsb;\r
106extern d10 spt, cst, cstm, pur;\r
107extern a10 dbr1, dbr2, dbr3, dbr4;\r
108extern d10 pcst, quant;\r
109extern t_bool paging;\r
110extern UNIT cpu_unit;\r
111extern jmp_buf save_env;\r
112extern int32 test_int (void);\r
113extern int32 pi_eval (void);\r
114\r
115int32 eptbl[PTBL_MEMSIZE]; /* exec page table */\r
116int32 uptbl[PTBL_MEMSIZE]; /* user page table */\r
117int32 physptbl[PTBL_MEMSIZE]; /* phys page table */\r
118int32 *ptbl_cur, *ptbl_prv;\r
119int32 save_ea;\r
120\r
121int32 ptbl_fill (a10 ea, int32 *ptbl, int32 mode);\r
122t_stat pag_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);\r
123t_stat pag_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);\r
124t_stat pag_reset (DEVICE *dptr);\r
125void pag_nxm (a10 pa, int32 phys, int32 trap);\r
126\r
127/* Pager data structures\r
128\r
129 pag_dev pager device descriptor\r
130 pag_unit pager units\r
131 pager_reg pager register list\r
132*/\r
133\r
134UNIT pag_unit[] = {\r
135 { UDATA (NULL, UNIT_FIX, PTBL_MEMSIZE) },\r
136 { UDATA (NULL, UNIT_FIX, PTBL_MEMSIZE) }\r
137 };\r
138\r
139REG pag_reg[] = {\r
140 { ORDATA (PANIC_EA, save_ea, PASIZE), REG_HRO },\r
141 { NULL }\r
142 };\r
143\r
144DEVICE pag_dev = {\r
145 "PAG", pag_unit, pag_reg, NULL,\r
146 2, 8, PTBL_ASIZE, 1, 8, 32,\r
147 &pag_ex, &pag_dep, &pag_reset,\r
148 NULL, NULL, NULL,\r
149 NULL, 0\r
150 };\r
151\r
152/* Memory read and write routines\r
153\r
154 Read - read current or previous, read checking\r
155 ReadM - read current or previous, write checking\r
156 ReadE - read exec\r
157 ReadP - read physical\r
158 Write - write current or previous\r
159 WriteE - write exec\r
160 WriteP - write physical\r
161 AccChk - test accessibility of virtual address\r
162*/\r
163\r
164d10 Read (a10 ea, int32 prv)\r
165{\r
166int32 pa, vpn, xpte;\r
167\r
168if (ea < AC_NUM) return (prv? ac_prv[ea]: ac_cur[ea]); /* AC request */\r
169vpn = PAG_GETVPN (ea); /* get page num */\r
170xpte = prv? ptbl_prv[vpn]: ptbl_cur[vpn]; /* get exp pte */\r
171if (xpte == 0) xpte = ptbl_fill (ea, prv? ptbl_prv: ptbl_cur, PTF_RD);\r
172pa = PAG_XPTEPA (xpte, ea); /* calc phys addr */\r
173if (MEM_ADDR_NXM (pa)) pag_nxm (pa, REF_V, PF_TR); /* process nxm */\r
174return M[pa]; /* return data */\r
175}\r
176\r
177d10 ReadM (a10 ea, int32 prv)\r
178{\r
179int32 pa, vpn, xpte;\r
180\r
181if (ea < AC_NUM) return (prv? ac_prv[ea]: ac_cur[ea]); /* AC request */\r
182vpn = PAG_GETVPN (ea); /* get page num */\r
183xpte = prv? ptbl_prv[vpn]: ptbl_cur[vpn]; /* get exp pte */\r
184if (xpte >= 0) xpte = ptbl_fill (ea, prv? ptbl_prv: ptbl_cur, PTF_WR);\r
185pa = PAG_XPTEPA (xpte, ea); /* calc phys addr */\r
186if (MEM_ADDR_NXM (pa)) pag_nxm (pa, REF_V, PF_TR); /* process nxm */\r
187return M[pa]; /* return data */\r
188}\r
189\r
190d10 ReadE (a10 ea)\r
191{\r
192int32 pa, vpn, xpte;\r
193\r
194if (ea < AC_NUM) return AC(ea); /* AC? use current */\r
195if (!PAGING) return M[ea]; /* phys? no mapping */\r
196vpn = PAG_GETVPN (ea); /* get page num */\r
197xpte = eptbl[vpn]; /* get exp pte, exec tbl */\r
198if (xpte == 0) xpte = ptbl_fill (ea, eptbl, PTF_RD);\r
199pa = PAG_XPTEPA (xpte, ea); /* calc phys addr */\r
200if (MEM_ADDR_NXM (pa)) pag_nxm (pa, REF_V, PF_TR); /* process nxm */\r
201return M[pa]; /* return data */\r
202}\r
203\r
204d10 ReadP (a10 ea)\r
205{\r
206if (ea < AC_NUM) return AC(ea); /* AC request */\r
207if (MEM_ADDR_NXM (ea)) pag_nxm (ea, REF_P, PF_TR); /* process nxm */\r
208return M[ea]; /* return data */\r
209}\r
210\r
211void Write (a10 ea, d10 val, int32 prv)\r
212{\r
213int32 pa, vpn, xpte;\r
214\r
215if (ea < AC_NUM) { /* AC request */\r
216 if (prv) ac_prv[ea] = val; /* write AC */\r
217 else ac_cur[ea] = val;\r
218 }\r
219else {\r
220 vpn = PAG_GETVPN (ea); /* get page num */\r
221 xpte = prv? ptbl_prv[vpn]: ptbl_cur[vpn]; /* get exp pte */\r
222 if (xpte >= 0) xpte = ptbl_fill (ea, prv? ptbl_prv: ptbl_cur, PTF_WR);\r
223 pa = PAG_XPTEPA (xpte, ea); /* calc phys addr */\r
224 if (MEM_ADDR_NXM (pa)) pag_nxm (pa, REF_V, PF_TR); /* process nxm */\r
225 else M[pa] = val; /* write data */\r
226 }\r
227return;\r
228}\r
229\r
230void WriteE (a10 ea, d10 val)\r
231{\r
232int32 pa, vpn, xpte;\r
233\r
234if (ea < AC_NUM) AC(ea) = val; /* AC? use current */\r
235else if (!PAGING) M[ea] = val; /* phys? no mapping */\r
236else {\r
237 vpn = PAG_GETVPN (ea); /* get page num */\r
238 xpte = eptbl[vpn]; /* get exp pte, exec tbl */\r
239 if (xpte >= 0) xpte = ptbl_fill (ea, eptbl, PTF_WR);\r
240 pa = PAG_XPTEPA (xpte, ea); /* calc phys addr */\r
241 if (MEM_ADDR_NXM (pa)) pag_nxm (pa, REF_V, PF_TR); /* process nxm */\r
242 else M[pa] = val; /* write data */\r
243 }\r
244return;\r
245}\r
246\r
247void WriteP (a10 ea, d10 val)\r
248{\r
249if (ea < AC_NUM) AC(ea) = val; /* AC request */\r
250else {\r
251 if (MEM_ADDR_NXM (ea)) pag_nxm (ea, REF_P, PF_TR); /* process nxm */\r
252 M[ea] = val; /* memory */\r
253 }\r
254return;\r
255}\r
256\r
257t_bool AccViol (a10 ea, int32 prv, int32 mode)\r
258{\r
259int32 vpn, xpte;\r
260\r
261if (ea < AC_NUM) return FALSE; /* AC request */\r
262vpn = PAG_GETVPN (ea); /* get page num */\r
263xpte = prv? ptbl_prv[vpn]: ptbl_cur[vpn]; /* get exp pte */\r
264if ((xpte == 0) || ((mode & PTF_WR) && (xpte > 0))) /* not accessible? */\r
265 xpte = ptbl_fill (ea, prv? ptbl_prv: ptbl_cur, mode | PTF_MAP);\r
266if (xpte) return FALSE; /* accessible */\r
267return TRUE; /* not accessible */\r
268}\r
269\r
270void pag_nxm (a10 pa, int32 phys, int32 trap)\r
271{\r
272apr_flg = apr_flg | APRF_NXM; /* set APR flag */\r
273pi_eval (); /* eval intr */\r
274pager_word = PF_NXM | (phys? PF_NXMP: 0) |\r
275 (TSTF (F_USR)? PF_USER: 0) | ((d10) pa);\r
276if (PAGING && trap) ABORT (PAGE_FAIL); /* trap? */\r
277return;\r
278}\r
279\r
280/* Page table fill\r
281\r
282 This routine is called if the page table is invalid, or on a write\r
283 reference if the page table is read only. If the access is allowed\r
284 it stores the pte in the page table entry and returns an expanded\r
285 pte for use by the caller. Otherwise, it generates a page fail.\r
286\r
287 Notes:\r
288 - If called from the console, invalid references return a pte\r
289 of 0, and the page table entry is not filled.\r
290 - If called from MAP, invalid references return a pte of 0. The\r
291 page fail word is properly set up.\r
292*/\r
293\r
294#define PAGE_FAIL_TRAP if (mode & (PTF_CON | PTF_MAP)) return 0; \\r
295 ABORT (PAGE_FAIL)\r
296#define READPT(x,y) if (MEM_ADDR_NXM (y)) { \\r
297 pag_nxm (y, REF_P, PF_OK); \\r
298 PAGE_FAIL_TRAP; \\r
299 } \\r
300 x = ReadP (y)\r
301\r
302int32 ptbl_fill (a10 ea, int32 *tbl, int32 mode)\r
303{\r
304\r
305/* ITS paging is based on conventional page tables. ITS divides each address\r
306 space into a 128K high and low section, and uses different descriptor base\r
307 pointers (dbr) for each. ITS pages are twice the size of DEC standard;\r
308 therefore, the fill routine fills two page table entries and returns the pte\r
309 that maps the correct ITS half page. This allows the DEC paging macros to\r
310 be used in the normal path read-write routines.\r
311\r
312 ITS has no MAP instruction, therefore, physical NXM traps are ok.\r
313*/\r
314\r
315if (Q_ITS) { /* ITS paging */\r
316 int32 acc, decvpn, pte, vpn, ptead, xpte;\r
317 d10 ptewd;\r
318\r
319 vpn = ITS_GETVPN (ea); /* get ITS pagno */\r
320 if (tbl == uptbl)\r
321 ptead = ((ea & RSIGN)? dbr2: dbr1) + ((vpn >> 1) & 077);\r
322 else ptead = ((ea & RSIGN)? dbr3: dbr4) + ((vpn >> 1) & 077);\r
323 ptewd = ReadP (ptead); /* get PTE pair */\r
324 pte = (int32) ((ptewd >> ((vpn & 1)? 0: 18)) & RMASK);\r
325 acc = ITS_GETACC (pte); /* get access */\r
326 pager_word = PF_VIRT | ea | ((tbl == uptbl)? PF_USER: 0) |\r
327 ((mode & PTF_WR)? PF_ITS_WRITE: 0) | (acc << PF_ITS_V_ACC);\r
328 if ((acc != ITS_ACC_NO) && (!(mode & PTF_WR) || (acc == ITS_ACC_RW))) { \r
329 pte = pte & ~PTE_ITS_AGE; /* clear age */\r
330 if (vpn & 1) WriteP (ptead, (ptewd & LMASK) | pte);\r
331 else WriteP (ptead, (ptewd & RMASK) | (((d10) pte) << 18));\r
332 xpte = ((pte & PTE_ITS_PPMASK) << ITS_V_PN) | PTBL_V |\r
333 ((acc == ITS_ACC_RW)? PTBL_M: 0);\r
334 decvpn = PAG_GETVPN (ea); /* get tlb idx */\r
335 if (!(mode & PTF_CON)) {\r
336 tbl[decvpn & ~1] = xpte; /* map lo ITS page */\r
337 tbl[decvpn | 1] = xpte + PAG_SIZE; /* map hi */\r
338 }\r
339 return (xpte + ((decvpn & 1)? PAG_SIZE: 0));\r
340 }\r
341 PAGE_FAIL_TRAP;\r
342 } /* end ITS paging */\r
343\r
344/* TOPS-10 paging - checked against KS10 microcode\r
345\r
346 TOPS-10 paging is also based on conventional page tables. The user page\r
347 tables are arranged contiguously at the beginning of the user process table;\r
348 however, the executive page tables are scattered through the executive and\r
349 user process tables.\r
350*/\r
351\r
352else if (!T20PAG) { /* TOPS-10 paging */\r
353 int32 pte, vpn, ptead, xpte;\r
354 d10 ptewd;\r
355\r
356 vpn = PAG_GETVPN (ea); /* get virt page num */\r
357 if (tbl == uptbl) ptead = upta + UPT_T10_UMAP + (vpn >> 1);\r
358 else if (vpn < 0340) ptead = epta + EPT_T10_X000 + (vpn >> 1);\r
359 else if (vpn < 0400) ptead = upta + UPT_T10_X340 + ((vpn - 0340) >> 1);\r
360 else ptead = epta + EPT_T10_X400 + ((vpn - 0400) >> 1);\r
361 READPT (ptewd, ptead); /* get PTE pair */\r
362 pte = (int32) ((ptewd >> ((vpn & 1)? 0: 18)) & RMASK);\r
363 pager_word = PF_VIRT | ea | ((tbl == uptbl)? PF_USER: 0) |\r
364 ((mode & PTF_WR)? PF_WRITE: 0) |\r
365 ((pte & PTE_T10_A)? PF_T10_A |\r
366 ((pte & PTE_T10_S)? PF_T10_S: 0): 0);\r
367 if (mode & PTF_MAP) pager_word = pager_word | /* map? add to pf wd */\r
368 ((pte & PTE_T10_W)? PF_T10_W: 0) | /* W, S, C bits */\r
369 ((pte & PTE_T10_S)? PF_T10_S: 0) |\r
370 ((pte & PTE_T10_C)? PF_C: 0);\r
371 if ((pte & PTE_T10_A) && (!(mode & PTF_WR) || (pte & PTE_T10_W))) {\r
372 xpte = ((pte & PTE_PPMASK) << PAG_V_PN) | /* calc exp pte */\r
373 PTBL_V | ((pte & PTE_T10_W)? PTBL_M: 0);\r
374 if (!(mode & PTF_CON)) tbl[vpn] = xpte; /* set tbl if ~cons */\r
375 return xpte;\r
376 }\r
377 PAGE_FAIL_TRAP;\r
378 } /* end TOPS10 paging */\r
379\r
380/* TOPS-20 paging - checked against KS10 microcode\r
381\r
382 TOPS-20 paging has three phases:\r
383\r
384 1. Starting at EPT/UPT + 540 + section number, chase section pointers to\r
385 get the pointer to the section page table. In the KS10, because there\r
386 is only one section, the microcode caches the result of this evaluation.\r
387 Also, the evaluation of indirect pointers is simplified, as the section\r
388 table index is ignored.\r
389\r
390 2. Starting with the page map pointer, chase page pointers to get the\r
391 pointer to the page. The KS10 allows the operating system to inhibit\r
392 updating of the CST (base address = 0).\r
393\r
394 3. Use the page pointer to get the CST entry. If a write reference to\r
395 a writeable page, set CST_M. If CST_M is set, set M in page table.\r
396*/\r
397\r
398else { /* TOPS-20 paging */\r
399 int32 pmi, vpn, xpte;\r
400 int32 flg, t;\r
401 t_bool stop;\r
402 a10 pa, csta;\r
403 d10 ptr, cste;\r
404 d10 acc = PTE_T20_W | PTE_T20_C; /* init access bits */\r
405\r
406 pager_word = PF_VIRT | ea | ((tbl == uptbl)? PF_USER: 0) |\r
407 ((mode & PTF_WR)? PF_WRITE: 0); /* set page fail word */\r
408\r
409/* First phase - evaluate section pointers - returns a ptr to a page map\r
410 As a single section machine, the KS10 short circuits this part of the\r
411 process. In particular, the indirect pointer calculation assumes that\r
412 the section table index will be 0. It adds the full pointer (not just\r
413 the right half) to the SPT base. If the section index is > 0, the\r
414 result is a physical memory address > 256KW. Depending on the size of\r
415 memory, the SPT fetch may or may not generate a NXM page fail. The\r
416 KS10 then ignores the section table index in fetching the next pointer.\r
417\r
418 The KS10 KL10 memory management diagnostic (dskec.sav) tests for this\r
419 behavior with a section index of 3. However, this would be a legal\r
420 physical address in a system with 1MW. Accordingly, the simulator\r
421 special cases non-zero section indices (which can't work in any case)\r
422 to generate the right behavior for the diagnostic.\r
423*/\r
424\r
425 vpn = PAG_GETVPN (ea); /* get virt page num */\r
426 pa = (tbl == uptbl)? upta + UPT_T20_SCTN: epta + EPT_T20_SCTN;\r
427 READPT (ptr, pa & PAMASK); /* get section 0 ptr */\r
428 for (stop = FALSE, flg = 0; !stop; flg++) { /* eval section ptrs */\r
429 acc = acc & ptr; /* cascade acc bits */\r
430 switch (T20_GETTYP (ptr)) { /* case on ptr type */\r
431\r
432 case T20_NOA: /* no access */\r
433 default: /* undefined type */\r
434 PAGE_FAIL_TRAP; /* page fail */\r
435\r
436 case T20_IMM: /* immediate */\r
437 stop = TRUE; /* exit */\r
438 break;\r
439\r
440 case T20_SHR: /* shared */\r
441 pa = (int32) (spt + (ptr & RMASK)); /* get SPT idx */\r
442 READPT (ptr, pa & PAMASK); /* get SPT entry */\r
443 stop = TRUE; /* exit */\r
444 break;\r
445\r
446 case T20_IND: /* indirect */\r
447 if (flg && (t = test_int ())) ABORT (t);\r
448 pmi = T20_GETPMI (ptr); /* get sect tbl idx */\r
449 pa = (int32) (spt + (ptr & RMASK)); /* get SPT idx */\r
450 if (pmi) { /* for dskec */\r
451 pag_nxm ((pmi << 18) | pa, REF_P, PF_OK);\r
452 PAGE_FAIL_TRAP;\r
453 }\r
454 READPT (ptr, pa & PAMASK); /* get SPT entry */\r
455 if (ptr & PTE_T20_STM) { PAGE_FAIL_TRAP; }\r
456 pa = PAG_PTEPA (ptr, pmi); /* index off page */\r
457 READPT (ptr, pa & PAMASK); /* get pointer */\r
458 break; /* continue in loop */\r
459 } /* end case */\r
460 } /* end for */\r
461\r
462/* Second phase - found page map ptr, evaluate page pointers */\r
463\r
464 pa = PAG_PTEPA (ptr, vpn); /* get ptbl address */\r
465 for (stop = FALSE, flg = 0; !stop; flg++) { /* eval page ptrs */\r
466 if (ptr & PTE_T20_STM) { PAGE_FAIL_TRAP; } /* non-res? */\r
467 if (cst) { /* cst really there? */\r
468 csta = (int32) ((cst + (ptr & PTE_PPMASK)) & PAMASK);\r
469 READPT (cste, csta); /* get CST entry */\r
470 if ((cste & CST_AGE) == 0) { PAGE_FAIL_TRAP; }\r
471 cste = (cste & cstm) | pur; /* update entry */\r
472 WriteP (csta, cste); /* rewrite */\r
473 }\r
474 READPT (ptr, pa & PAMASK); /* get pointer */\r
475 acc = acc & ptr; /* cascade acc bits */\r
476 switch (T20_GETTYP (ptr)) { /* case on ptr type */\r
477\r
478 case T20_NOA: /* no access */\r
479 default: /* undefined type */\r
480 PAGE_FAIL_TRAP; /* page fail */\r
481\r
482 case T20_IMM: /* immediate */\r
483 stop = TRUE; /* exit */\r
484 break;\r
485\r
486 case T20_SHR: /* shared */\r
487 pa = (int32) (spt + (ptr & RMASK)); /* get SPT idx */\r
488 READPT (ptr, pa & PAMASK); /* get SPT entry */\r
489 stop = TRUE; /* exit */\r
490 break;\r
491\r
492 case T20_IND: /* indirect */\r
493 if (flg && (t = test_int ())) ABORT (t);\r
494 pmi = T20_GETPMI (ptr); /* get section index */\r
495 pa = (int32) (spt + (ptr & RMASK)); /* get SPT idx */\r
496 READPT (ptr, pa & PAMASK); /* get SPT entry */\r
497 pa = PAG_PTEPA (ptr, pmi); /* index off page */\r
498 break; /* continue in loop */\r
499 } /* end case */\r
500 } /* end for */\r
501\r
502/* Last phase - have final page pointer, check modifiability */\r
503\r
504 if (ptr & PTE_T20_STM) { PAGE_FAIL_TRAP; } /* non-resident? */\r
505 if (cst) { /* CST really there? */\r
506 csta = (int32) ((cst + (ptr & PTE_PPMASK)) & PAMASK);\r
507 READPT (cste, csta); /* get CST entry */\r
508 if ((cste & CST_AGE) == 0) { PAGE_FAIL_TRAP; }\r
509 cste = (cste & cstm) | pur; /* update entry */\r
510 }\r
511 else cste = 0; /* no, entry = 0 */\r
512 pager_word = pager_word | PF_T20_DN; /* set eval done */\r
513 xpte = ((int32) ((ptr & PTE_PPMASK) << PAG_V_PN)) | PTBL_V;\r
514 if (mode & PTF_WR) { /* write? */\r
515 if (acc & PTE_T20_W) { /* writable? */\r
516 xpte = xpte | PTBL_M; /* set PTE M */\r
517 cste = cste | CST_M; /* set CST M */\r
518 }\r
519 else { PAGE_FAIL_TRAP; } /* no, trap */\r
520 }\r
521 if (cst) WriteP (csta, cste); /* write CST entry */\r
522 if (mode & PTF_MAP) pager_word = pager_word | /* map? more in pf wd */\r
523 ((xpte & PTBL_M)? PF_T20_M: 0) | /* M, W, C bits */\r
524 ((acc & PTE_T20_W)? PF_T20_W: 0) |\r
525 ((acc & PTE_T20_C)? PF_C: 0);\r
526 if (!(mode & PTF_CON)) tbl[vpn] = xpte; /* set tbl if ~cons */\r
527 return xpte;\r
528 } /* end TOPS20 paging */\r
529}\r
530\r
531/* Set up pointers for AC, memory, and process table access */\r
532\r
533void set_dyn_ptrs (void)\r
534{\r
535int32 t;\r
536\r
537if (PAGING) {\r
538 ac_cur = &acs[UBR_GETCURAC (ubr) * AC_NUM];\r
539 ac_prv = &acs[UBR_GETPRVAC (ubr) * AC_NUM];\r
540 if (TSTF (F_USR)) ptbl_cur = ptbl_prv = &uptbl[0];\r
541 else {\r
542 ptbl_cur = &eptbl[0];\r
543 ptbl_prv = TSTF (F_UIO)? &uptbl[0]: &eptbl[0];\r
544 }\r
545 }\r
546else {\r
547 ac_cur = ac_prv = &acs[0];\r
548 ptbl_cur = ptbl_prv = &physptbl[0];\r
549 }\r
550t = EBR_GETEBR (ebr);\r
551epta = t << PAG_V_PN;\r
552if (Q_ITS) upta = (int32) ubr & PAMASK;\r
553else {\r
554 t = UBR_GETUBR (ubr);\r
555 upta = t << PAG_V_PN;\r
556 }\r
557return;\r
558}\r
559\r
560/* MAP instruction, TOPS-10 and TOPS-20 only\r
561\r
562 According to the KS-10 ucode, map with paging disabled sets\r
563 "accessible, writeable, software", regardless of whether\r
564 TOPS-10 or TOPS-20 paging is implemented\r
565*/\r
566\r
567d10 map (a10 ea, int32 prv)\r
568{\r
569int32 xpte;\r
570d10 val = (TSTF (F_USR)? PF_USER: 0);\r
571\r
572if (!PAGING) return (val | PF_T10_A | PF_T10_W | PF_T10_S | ea);\r
573xpte = ptbl_fill (ea, prv? ptbl_prv: ptbl_cur, PTF_MAP); /* get exp pte */\r
574if (xpte) val = (pager_word & ~PAMASK) | PAG_XPTEPA (xpte, ea);\r
575else {\r
576 if (pager_word & PF_HARD) val = pager_word; /* hard error */\r
577 else val = val | PF_VIRT | ea; /* inaccessible */\r
578 }\r
579return val;\r
580}\r
581\r
582/* Mapping routine for console */\r
583\r
584a10 conmap (a10 ea, int32 mode, int32 sw)\r
585{\r
586int32 xpte, *tbl;\r
587\r
588if (!PAGING) return ea;\r
589set_dyn_ptrs (); /* in case changed */\r
590if (sw & SWMASK ('E')) tbl = eptbl;\r
591else if (sw & SWMASK ('U')) tbl = uptbl;\r
592else tbl = ptbl_cur;\r
593xpte = ptbl_fill (ea, tbl, mode);\r
594if (xpte) return PAG_XPTEPA (xpte, ea);\r
595else return MAXMEMSIZE;\r
596}\r
597\r
598/* Common pager instructions */\r
599\r
600t_bool clrpt (a10 ea, int32 prv)\r
601{\r
602int32 vpn = PAG_GETVPN (ea); /* get page num */\r
603\r
604if (Q_ITS) { /* ITS? */\r
605 uptbl[vpn & ~1] = 0; /* clear double size */\r
606 uptbl[vpn | 1] = 0; /* entries in */\r
607 eptbl[vpn & ~1] = 0; /* both page tables */\r
608 eptbl[vpn | 1] = 0;\r
609 }\r
610else {\r
611 uptbl[vpn] = 0; /* clear entries in */\r
612 eptbl[vpn] = 0; /* both page tables */\r
613 }\r
614return FALSE;\r
615} \r
616\r
617t_bool wrebr (a10 ea, int32 prv)\r
618{\r
619ebr = ea & EBR_MASK; /* store EBR */\r
620pag_reset (&pag_dev); /* clear page tables */\r
621set_dyn_ptrs (); /* set dynamic ptrs */\r
622return FALSE;\r
623}\r
624\r
625t_bool rdebr (a10 ea, int32 prv)\r
626{\r
627Write (ea, (ebr & EBR_MASK), prv);\r
628return FALSE;\r
629}\r
630\r
631t_bool wrubr (a10 ea, int32 prv)\r
632{\r
633d10 val = Read (ea, prv);\r
634d10 ubr_mask = (Q_ITS)? PAMASK: UBR_UBRMASK; /* ITS: ubr is wd addr */\r
635\r
636if (val & UBR_SETACB) ubr = ubr & ~UBR_ACBMASK; /* set AC's? */\r
637else val = val & ~UBR_ACBMASK; /* no, keep old val */\r
638if (val & UBR_SETUBR) { /* set UBR? */\r
639 ubr = ubr & ~ubr_mask;\r
640 pag_reset (&pag_dev); /* yes, clr pg tbls */\r
641 }\r
642else val = val & ~ubr_mask; /* no, keep old val */\r
643ubr = (ubr | val) & (UBR_ACBMASK | ubr_mask);\r
644set_dyn_ptrs ();\r
645return FALSE;\r
646}\r
647\r
648t_bool rdubr (a10 ea, int32 prv)\r
649{\r
650ubr = ubr & (UBR_ACBMASK | (Q_ITS? PAMASK: UBR_UBRMASK));\r
651Write (ea, UBRWORD, prv);\r
652return FALSE;\r
653}\r
654\r
655t_bool wrhsb (a10 ea, int32 prv)\r
656{\r
657hsb = Read (ea, prv) & PAMASK;\r
658return FALSE;\r
659}\r
660\r
661t_bool rdhsb (a10 ea, int32 prv)\r
662{\r
663Write (ea, hsb, prv);\r
664return FALSE;\r
665}\r
666\r
667/* TOPS20 pager instructions */\r
668\r
669t_bool wrspb (a10 ea, int32 prv)\r
670{\r
671spt = Read (ea, prv);\r
672return FALSE;\r
673}\r
674\r
675t_bool rdspb (a10 ea, int32 prv)\r
676{\r
677Write (ea, spt, prv);\r
678return FALSE;\r
679}\r
680\r
681t_bool wrcsb (a10 ea, int32 prv)\r
682{\r
683cst = Read (ea, prv);\r
684return FALSE;\r
685}\r
686\r
687t_bool rdcsb (a10 ea, int32 prv)\r
688{\r
689Write (ea, cst, prv);\r
690return FALSE;\r
691}\r
692\r
693t_bool wrpur (a10 ea, int32 prv)\r
694{\r
695pur = Read (ea, prv);\r
696return FALSE;\r
697}\r
698\r
699t_bool rdpur (a10 ea, int32 prv)\r
700{\r
701Write (ea, pur, prv);\r
702return FALSE;\r
703}\r
704\r
705t_bool wrcstm (a10 ea, int32 prv)\r
706{\r
707cstm = Read (ea, prv);\r
708if ((cpu_unit.flags & UNIT_T20) && (ea == 040127))\r
709 cstm = 0770000000000;\r
710return FALSE;\r
711}\r
712\r
713t_bool rdcstm (a10 ea, int32 prv)\r
714{\r
715Write (ea, cstm, prv);\r
716return FALSE;\r
717}\r
718\r
719/* ITS pager instructions\r
720 The KS10 does not implement the JPC option.\r
721*/\r
722\r
723t_bool clrcsh (a10 ea, int32 prv)\r
724{\r
725return FALSE;\r
726}\r
727\r
728t_bool ldbr1 (a10 ea, int32 prv)\r
729{\r
730dbr1 = ea;\r
731pag_reset (&pag_dev);\r
732return FALSE;\r
733}\r
734\r
735t_bool sdbr1 (a10 ea, int32 prv)\r
736{\r
737Write (ea, dbr1, prv);\r
738return FALSE;\r
739}\r
740\r
741t_bool ldbr2 (a10 ea, int32 prv)\r
742{\r
743dbr2 = ea;\r
744pag_reset (&pag_dev);\r
745return FALSE;\r
746}\r
747\r
748t_bool sdbr2 (a10 ea, int32 prv)\r
749{\r
750Write (ea, dbr2, prv);\r
751return FALSE;\r
752}\r
753\r
754t_bool ldbr3 (a10 ea, int32 prv)\r
755{\r
756dbr3 = ea;\r
757pag_reset (&pag_dev);\r
758return FALSE;\r
759}\r
760\r
761t_bool sdbr3 (a10 ea, int32 prv)\r
762{\r
763Write (ea, dbr3, prv);\r
764return FALSE;\r
765}\r
766\r
767t_bool ldbr4 (a10 ea, int32 prv)\r
768{\r
769dbr4 = ea;\r
770pag_reset (&pag_dev);\r
771return FALSE;\r
772}\r
773\r
774t_bool sdbr4 (a10 ea, int32 prv)\r
775{\r
776Write (ea, dbr4, prv);\r
777return FALSE;\r
778}\r
779\r
780t_bool wrpcst (a10 ea, int32 prv)\r
781{\r
782pcst = Read (ea, prv);\r
783return FALSE;\r
784}\r
785\r
786t_bool rdpcst (a10 ea, int32 prv)\r
787{\r
788Write (ea, pcst, prv);\r
789return FALSE;\r
790}\r
791\r
792t_bool lpmr (a10 ea, int32 prv)\r
793{\r
794d10 val;\r
795\r
796val = Read (ADDA (ea, 2), prv);\r
797dbr1 = (a10) (Read (ea, prv) & AMASK);\r
798dbr2 = (a10) (Read (ADDA (ea, 1), prv) & AMASK);\r
799quant = val;\r
800pag_reset (&pag_dev);\r
801return FALSE;\r
802}\r
803\r
804t_bool spm (a10 ea, int32 prv)\r
805{\r
806\r
807ReadM (ADDA (ea, 2), prv);\r
808Write (ea, dbr1, prv);\r
809Write (ADDA (ea, 1), dbr2, prv);\r
810Write (ADDA (ea, 2), quant, prv);\r
811return FALSE;\r
812}\r
813\r
814/* Simulator interface routines */\r
815\r
816t_stat pag_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)\r
817{\r
818int32 tbln = uptr - pag_unit;\r
819\r
820if (addr >= PTBL_MEMSIZE) return SCPE_NXM;\r
821*vptr = tbln? uptbl[addr]: eptbl[addr];;\r
822return SCPE_OK;\r
823}\r
824\r
825t_stat pag_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)\r
826{\r
827int32 tbln = uptr - pag_unit;\r
828\r
829if (addr >= PTBL_MEMSIZE) return SCPE_NXM;\r
830if (tbln) uptbl[addr] = (int32) val & PTBL_MASK;\r
831else eptbl[addr] = (int32) val & PTBL_MASK;\r
832return SCPE_OK;\r
833}\r
834\r
835t_stat pag_reset (DEVICE *dptr)\r
836{\r
837int32 i;\r
838\r
839for (i = 0; i < PTBL_MEMSIZE; i++) {\r
840 eptbl[i] = uptbl[i] = 0;\r
841 physptbl[i] = (i << PAG_V_PN) + PTBL_M + PTBL_V;\r
842 }\r
843return SCPE_OK;\r
844}\r