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