Commit | Line | Data |
---|---|---|
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 | |
98 | extern d10 *M;\r | |
99 | extern d10 acs[AC_NBLK * AC_NUM];\r | |
100 | extern d10 *ac_cur, *ac_prv, *last_pa;\r | |
101 | extern a10 epta, upta;\r | |
102 | extern int32 flags;\r | |
103 | extern d10 pager_word;\r | |
104 | extern int32 apr_flg;\r | |
105 | extern d10 ebr, ubr, hsb;\r | |
106 | extern d10 spt, cst, cstm, pur;\r | |
107 | extern a10 dbr1, dbr2, dbr3, dbr4;\r | |
108 | extern d10 pcst, quant;\r | |
109 | extern t_bool paging;\r | |
110 | extern UNIT cpu_unit;\r | |
111 | extern jmp_buf save_env;\r | |
112 | extern int32 test_int (void);\r | |
113 | extern int32 pi_eval (void);\r | |
114 | \r | |
115 | int32 eptbl[PTBL_MEMSIZE]; /* exec page table */\r | |
116 | int32 uptbl[PTBL_MEMSIZE]; /* user page table */\r | |
117 | int32 physptbl[PTBL_MEMSIZE]; /* phys page table */\r | |
118 | int32 *ptbl_cur, *ptbl_prv;\r | |
119 | int32 save_ea;\r | |
120 | \r | |
121 | int32 ptbl_fill (a10 ea, int32 *ptbl, int32 mode);\r | |
122 | t_stat pag_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);\r | |
123 | t_stat pag_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);\r | |
124 | t_stat pag_reset (DEVICE *dptr);\r | |
125 | void 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 | |
134 | UNIT pag_unit[] = {\r | |
135 | { UDATA (NULL, UNIT_FIX, PTBL_MEMSIZE) },\r | |
136 | { UDATA (NULL, UNIT_FIX, PTBL_MEMSIZE) }\r | |
137 | };\r | |
138 | \r | |
139 | REG pag_reg[] = {\r | |
140 | { ORDATA (PANIC_EA, save_ea, PASIZE), REG_HRO },\r | |
141 | { NULL }\r | |
142 | };\r | |
143 | \r | |
144 | DEVICE 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 | |
164 | d10 Read (a10 ea, int32 prv)\r | |
165 | {\r | |
166 | int32 pa, vpn, xpte;\r | |
167 | \r | |
168 | if (ea < AC_NUM) return (prv? ac_prv[ea]: ac_cur[ea]); /* AC request */\r | |
169 | vpn = PAG_GETVPN (ea); /* get page num */\r | |
170 | xpte = prv? ptbl_prv[vpn]: ptbl_cur[vpn]; /* get exp pte */\r | |
171 | if (xpte == 0) xpte = ptbl_fill (ea, prv? ptbl_prv: ptbl_cur, PTF_RD);\r | |
172 | pa = PAG_XPTEPA (xpte, ea); /* calc phys addr */\r | |
173 | if (MEM_ADDR_NXM (pa)) pag_nxm (pa, REF_V, PF_TR); /* process nxm */\r | |
174 | return M[pa]; /* return data */\r | |
175 | }\r | |
176 | \r | |
177 | d10 ReadM (a10 ea, int32 prv)\r | |
178 | {\r | |
179 | int32 pa, vpn, xpte;\r | |
180 | \r | |
181 | if (ea < AC_NUM) return (prv? ac_prv[ea]: ac_cur[ea]); /* AC request */\r | |
182 | vpn = PAG_GETVPN (ea); /* get page num */\r | |
183 | xpte = prv? ptbl_prv[vpn]: ptbl_cur[vpn]; /* get exp pte */\r | |
184 | if (xpte >= 0) xpte = ptbl_fill (ea, prv? ptbl_prv: ptbl_cur, PTF_WR);\r | |
185 | pa = PAG_XPTEPA (xpte, ea); /* calc phys addr */\r | |
186 | if (MEM_ADDR_NXM (pa)) pag_nxm (pa, REF_V, PF_TR); /* process nxm */\r | |
187 | return M[pa]; /* return data */\r | |
188 | }\r | |
189 | \r | |
190 | d10 ReadE (a10 ea)\r | |
191 | {\r | |
192 | int32 pa, vpn, xpte;\r | |
193 | \r | |
194 | if (ea < AC_NUM) return AC(ea); /* AC? use current */\r | |
195 | if (!PAGING) return M[ea]; /* phys? no mapping */\r | |
196 | vpn = PAG_GETVPN (ea); /* get page num */\r | |
197 | xpte = eptbl[vpn]; /* get exp pte, exec tbl */\r | |
198 | if (xpte == 0) xpte = ptbl_fill (ea, eptbl, PTF_RD);\r | |
199 | pa = PAG_XPTEPA (xpte, ea); /* calc phys addr */\r | |
200 | if (MEM_ADDR_NXM (pa)) pag_nxm (pa, REF_V, PF_TR); /* process nxm */\r | |
201 | return M[pa]; /* return data */\r | |
202 | }\r | |
203 | \r | |
204 | d10 ReadP (a10 ea)\r | |
205 | {\r | |
206 | if (ea < AC_NUM) return AC(ea); /* AC request */\r | |
207 | if (MEM_ADDR_NXM (ea)) pag_nxm (ea, REF_P, PF_TR); /* process nxm */\r | |
208 | return M[ea]; /* return data */\r | |
209 | }\r | |
210 | \r | |
211 | void Write (a10 ea, d10 val, int32 prv)\r | |
212 | {\r | |
213 | int32 pa, vpn, xpte;\r | |
214 | \r | |
215 | if (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 | |
219 | else {\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 | |
227 | return;\r | |
228 | }\r | |
229 | \r | |
230 | void WriteE (a10 ea, d10 val)\r | |
231 | {\r | |
232 | int32 pa, vpn, xpte;\r | |
233 | \r | |
234 | if (ea < AC_NUM) AC(ea) = val; /* AC? use current */\r | |
235 | else if (!PAGING) M[ea] = val; /* phys? no mapping */\r | |
236 | else {\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 | |
244 | return;\r | |
245 | }\r | |
246 | \r | |
247 | void WriteP (a10 ea, d10 val)\r | |
248 | {\r | |
249 | if (ea < AC_NUM) AC(ea) = val; /* AC request */\r | |
250 | else {\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 | |
254 | return;\r | |
255 | }\r | |
256 | \r | |
257 | t_bool AccViol (a10 ea, int32 prv, int32 mode)\r | |
258 | {\r | |
259 | int32 vpn, xpte;\r | |
260 | \r | |
261 | if (ea < AC_NUM) return FALSE; /* AC request */\r | |
262 | vpn = PAG_GETVPN (ea); /* get page num */\r | |
263 | xpte = prv? ptbl_prv[vpn]: ptbl_cur[vpn]; /* get exp pte */\r | |
264 | if ((xpte == 0) || ((mode & PTF_WR) && (xpte > 0))) /* not accessible? */\r | |
265 | xpte = ptbl_fill (ea, prv? ptbl_prv: ptbl_cur, mode | PTF_MAP);\r | |
266 | if (xpte) return FALSE; /* accessible */\r | |
267 | return TRUE; /* not accessible */\r | |
268 | }\r | |
269 | \r | |
270 | void pag_nxm (a10 pa, int32 phys, int32 trap)\r | |
271 | {\r | |
272 | apr_flg = apr_flg | APRF_NXM; /* set APR flag */\r | |
273 | pi_eval (); /* eval intr */\r | |
274 | pager_word = PF_NXM | (phys? PF_NXMP: 0) |\r | |
275 | (TSTF (F_USR)? PF_USER: 0) | ((d10) pa);\r | |
276 | if (PAGING && trap) ABORT (PAGE_FAIL); /* trap? */\r | |
277 | return;\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 | |
302 | int32 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 | |
315 | if (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 | |
352 | else 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 | |
398 | else { /* 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 | |
533 | void set_dyn_ptrs (void)\r | |
534 | {\r | |
535 | int32 t;\r | |
536 | \r | |
537 | if (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 | |
546 | else {\r | |
547 | ac_cur = ac_prv = &acs[0];\r | |
548 | ptbl_cur = ptbl_prv = &physptbl[0];\r | |
549 | }\r | |
550 | t = EBR_GETEBR (ebr);\r | |
551 | epta = t << PAG_V_PN;\r | |
552 | if (Q_ITS) upta = (int32) ubr & PAMASK;\r | |
553 | else {\r | |
554 | t = UBR_GETUBR (ubr);\r | |
555 | upta = t << PAG_V_PN;\r | |
556 | }\r | |
557 | return;\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 | |
567 | d10 map (a10 ea, int32 prv)\r | |
568 | {\r | |
569 | int32 xpte;\r | |
570 | d10 val = (TSTF (F_USR)? PF_USER: 0);\r | |
571 | \r | |
572 | if (!PAGING) return (val | PF_T10_A | PF_T10_W | PF_T10_S | ea);\r | |
573 | xpte = ptbl_fill (ea, prv? ptbl_prv: ptbl_cur, PTF_MAP); /* get exp pte */\r | |
574 | if (xpte) val = (pager_word & ~PAMASK) | PAG_XPTEPA (xpte, ea);\r | |
575 | else {\r | |
576 | if (pager_word & PF_HARD) val = pager_word; /* hard error */\r | |
577 | else val = val | PF_VIRT | ea; /* inaccessible */\r | |
578 | }\r | |
579 | return val;\r | |
580 | }\r | |
581 | \r | |
582 | /* Mapping routine for console */\r | |
583 | \r | |
584 | a10 conmap (a10 ea, int32 mode, int32 sw)\r | |
585 | {\r | |
586 | int32 xpte, *tbl;\r | |
587 | \r | |
588 | if (!PAGING) return ea;\r | |
589 | set_dyn_ptrs (); /* in case changed */\r | |
590 | if (sw & SWMASK ('E')) tbl = eptbl;\r | |
591 | else if (sw & SWMASK ('U')) tbl = uptbl;\r | |
592 | else tbl = ptbl_cur;\r | |
593 | xpte = ptbl_fill (ea, tbl, mode);\r | |
594 | if (xpte) return PAG_XPTEPA (xpte, ea);\r | |
595 | else return MAXMEMSIZE;\r | |
596 | }\r | |
597 | \r | |
598 | /* Common pager instructions */\r | |
599 | \r | |
600 | t_bool clrpt (a10 ea, int32 prv)\r | |
601 | {\r | |
602 | int32 vpn = PAG_GETVPN (ea); /* get page num */\r | |
603 | \r | |
604 | if (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 | |
610 | else {\r | |
611 | uptbl[vpn] = 0; /* clear entries in */\r | |
612 | eptbl[vpn] = 0; /* both page tables */\r | |
613 | }\r | |
614 | return FALSE;\r | |
615 | } \r | |
616 | \r | |
617 | t_bool wrebr (a10 ea, int32 prv)\r | |
618 | {\r | |
619 | ebr = ea & EBR_MASK; /* store EBR */\r | |
620 | pag_reset (&pag_dev); /* clear page tables */\r | |
621 | set_dyn_ptrs (); /* set dynamic ptrs */\r | |
622 | return FALSE;\r | |
623 | }\r | |
624 | \r | |
625 | t_bool rdebr (a10 ea, int32 prv)\r | |
626 | {\r | |
627 | Write (ea, (ebr & EBR_MASK), prv);\r | |
628 | return FALSE;\r | |
629 | }\r | |
630 | \r | |
631 | t_bool wrubr (a10 ea, int32 prv)\r | |
632 | {\r | |
633 | d10 val = Read (ea, prv);\r | |
634 | d10 ubr_mask = (Q_ITS)? PAMASK: UBR_UBRMASK; /* ITS: ubr is wd addr */\r | |
635 | \r | |
636 | if (val & UBR_SETACB) ubr = ubr & ~UBR_ACBMASK; /* set AC's? */\r | |
637 | else val = val & ~UBR_ACBMASK; /* no, keep old val */\r | |
638 | if (val & UBR_SETUBR) { /* set UBR? */\r | |
639 | ubr = ubr & ~ubr_mask;\r | |
640 | pag_reset (&pag_dev); /* yes, clr pg tbls */\r | |
641 | }\r | |
642 | else val = val & ~ubr_mask; /* no, keep old val */\r | |
643 | ubr = (ubr | val) & (UBR_ACBMASK | ubr_mask);\r | |
644 | set_dyn_ptrs ();\r | |
645 | return FALSE;\r | |
646 | }\r | |
647 | \r | |
648 | t_bool rdubr (a10 ea, int32 prv)\r | |
649 | {\r | |
650 | ubr = ubr & (UBR_ACBMASK | (Q_ITS? PAMASK: UBR_UBRMASK));\r | |
651 | Write (ea, UBRWORD, prv);\r | |
652 | return FALSE;\r | |
653 | }\r | |
654 | \r | |
655 | t_bool wrhsb (a10 ea, int32 prv)\r | |
656 | {\r | |
657 | hsb = Read (ea, prv) & PAMASK;\r | |
658 | return FALSE;\r | |
659 | }\r | |
660 | \r | |
661 | t_bool rdhsb (a10 ea, int32 prv)\r | |
662 | {\r | |
663 | Write (ea, hsb, prv);\r | |
664 | return FALSE;\r | |
665 | }\r | |
666 | \r | |
667 | /* TOPS20 pager instructions */\r | |
668 | \r | |
669 | t_bool wrspb (a10 ea, int32 prv)\r | |
670 | {\r | |
671 | spt = Read (ea, prv);\r | |
672 | return FALSE;\r | |
673 | }\r | |
674 | \r | |
675 | t_bool rdspb (a10 ea, int32 prv)\r | |
676 | {\r | |
677 | Write (ea, spt, prv);\r | |
678 | return FALSE;\r | |
679 | }\r | |
680 | \r | |
681 | t_bool wrcsb (a10 ea, int32 prv)\r | |
682 | {\r | |
683 | cst = Read (ea, prv);\r | |
684 | return FALSE;\r | |
685 | }\r | |
686 | \r | |
687 | t_bool rdcsb (a10 ea, int32 prv)\r | |
688 | {\r | |
689 | Write (ea, cst, prv);\r | |
690 | return FALSE;\r | |
691 | }\r | |
692 | \r | |
693 | t_bool wrpur (a10 ea, int32 prv)\r | |
694 | {\r | |
695 | pur = Read (ea, prv);\r | |
696 | return FALSE;\r | |
697 | }\r | |
698 | \r | |
699 | t_bool rdpur (a10 ea, int32 prv)\r | |
700 | {\r | |
701 | Write (ea, pur, prv);\r | |
702 | return FALSE;\r | |
703 | }\r | |
704 | \r | |
705 | t_bool wrcstm (a10 ea, int32 prv)\r | |
706 | {\r | |
707 | cstm = Read (ea, prv);\r | |
708 | if ((cpu_unit.flags & UNIT_T20) && (ea == 040127))\r | |
709 | cstm = 0770000000000;\r | |
710 | return FALSE;\r | |
711 | }\r | |
712 | \r | |
713 | t_bool rdcstm (a10 ea, int32 prv)\r | |
714 | {\r | |
715 | Write (ea, cstm, prv);\r | |
716 | return 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 | |
723 | t_bool clrcsh (a10 ea, int32 prv)\r | |
724 | {\r | |
725 | return FALSE;\r | |
726 | }\r | |
727 | \r | |
728 | t_bool ldbr1 (a10 ea, int32 prv)\r | |
729 | {\r | |
730 | dbr1 = ea;\r | |
731 | pag_reset (&pag_dev);\r | |
732 | return FALSE;\r | |
733 | }\r | |
734 | \r | |
735 | t_bool sdbr1 (a10 ea, int32 prv)\r | |
736 | {\r | |
737 | Write (ea, dbr1, prv);\r | |
738 | return FALSE;\r | |
739 | }\r | |
740 | \r | |
741 | t_bool ldbr2 (a10 ea, int32 prv)\r | |
742 | {\r | |
743 | dbr2 = ea;\r | |
744 | pag_reset (&pag_dev);\r | |
745 | return FALSE;\r | |
746 | }\r | |
747 | \r | |
748 | t_bool sdbr2 (a10 ea, int32 prv)\r | |
749 | {\r | |
750 | Write (ea, dbr2, prv);\r | |
751 | return FALSE;\r | |
752 | }\r | |
753 | \r | |
754 | t_bool ldbr3 (a10 ea, int32 prv)\r | |
755 | {\r | |
756 | dbr3 = ea;\r | |
757 | pag_reset (&pag_dev);\r | |
758 | return FALSE;\r | |
759 | }\r | |
760 | \r | |
761 | t_bool sdbr3 (a10 ea, int32 prv)\r | |
762 | {\r | |
763 | Write (ea, dbr3, prv);\r | |
764 | return FALSE;\r | |
765 | }\r | |
766 | \r | |
767 | t_bool ldbr4 (a10 ea, int32 prv)\r | |
768 | {\r | |
769 | dbr4 = ea;\r | |
770 | pag_reset (&pag_dev);\r | |
771 | return FALSE;\r | |
772 | }\r | |
773 | \r | |
774 | t_bool sdbr4 (a10 ea, int32 prv)\r | |
775 | {\r | |
776 | Write (ea, dbr4, prv);\r | |
777 | return FALSE;\r | |
778 | }\r | |
779 | \r | |
780 | t_bool wrpcst (a10 ea, int32 prv)\r | |
781 | {\r | |
782 | pcst = Read (ea, prv);\r | |
783 | return FALSE;\r | |
784 | }\r | |
785 | \r | |
786 | t_bool rdpcst (a10 ea, int32 prv)\r | |
787 | {\r | |
788 | Write (ea, pcst, prv);\r | |
789 | return FALSE;\r | |
790 | }\r | |
791 | \r | |
792 | t_bool lpmr (a10 ea, int32 prv)\r | |
793 | {\r | |
794 | d10 val;\r | |
795 | \r | |
796 | val = Read (ADDA (ea, 2), prv);\r | |
797 | dbr1 = (a10) (Read (ea, prv) & AMASK);\r | |
798 | dbr2 = (a10) (Read (ADDA (ea, 1), prv) & AMASK);\r | |
799 | quant = val;\r | |
800 | pag_reset (&pag_dev);\r | |
801 | return FALSE;\r | |
802 | }\r | |
803 | \r | |
804 | t_bool spm (a10 ea, int32 prv)\r | |
805 | {\r | |
806 | \r | |
807 | ReadM (ADDA (ea, 2), prv);\r | |
808 | Write (ea, dbr1, prv);\r | |
809 | Write (ADDA (ea, 1), dbr2, prv);\r | |
810 | Write (ADDA (ea, 2), quant, prv);\r | |
811 | return FALSE;\r | |
812 | }\r | |
813 | \r | |
814 | /* Simulator interface routines */\r | |
815 | \r | |
816 | t_stat pag_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)\r | |
817 | {\r | |
818 | int32 tbln = uptr - pag_unit;\r | |
819 | \r | |
820 | if (addr >= PTBL_MEMSIZE) return SCPE_NXM;\r | |
821 | *vptr = tbln? uptbl[addr]: eptbl[addr];;\r | |
822 | return SCPE_OK;\r | |
823 | }\r | |
824 | \r | |
825 | t_stat pag_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)\r | |
826 | {\r | |
827 | int32 tbln = uptr - pag_unit;\r | |
828 | \r | |
829 | if (addr >= PTBL_MEMSIZE) return SCPE_NXM;\r | |
830 | if (tbln) uptbl[addr] = (int32) val & PTBL_MASK;\r | |
831 | else eptbl[addr] = (int32) val & PTBL_MASK;\r | |
832 | return SCPE_OK;\r | |
833 | }\r | |
834 | \r | |
835 | t_stat pag_reset (DEVICE *dptr)\r | |
836 | {\r | |
837 | int32 i;\r | |
838 | \r | |
839 | for (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 | |
843 | return SCPE_OK;\r | |
844 | }\r |