1 /* pdp10_pag.c: PDP-10 paging subsystem simulator
3 Copyright (c) 1993-2005, Robert M Supnik
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:
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
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.
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.
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
36 The pager consists of a standard hardware part (the translation
37 tables) and an operating-system specific page table fill routine.
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.
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.
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.
66 The page fill routine is operating system dependent. Three styles
67 of paging are supported:
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
75 TOPS10 vs TOPS20 is selected by a bit in the EBR; ITS paging is
76 "hardwired" (it required different microcode).
79 #include "pdp10_defs.h"
82 /* Page table (contains expanded pte's) */
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)
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 */
99 extern d10 acs
[AC_NBLK
* AC_NUM
];
100 extern d10
*ac_cur
, *ac_prv
, *last_pa
;
101 extern a10 epta
, upta
;
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);
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
;
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
);
127 /* Pager data structures
129 pag_dev pager device descriptor
131 pager_reg pager register list
135 { UDATA (NULL
, UNIT_FIX
, PTBL_MEMSIZE
) },
136 { UDATA (NULL
, UNIT_FIX
, PTBL_MEMSIZE
) }
140 { ORDATA (PANIC_EA
, save_ea
, PASIZE
), REG_HRO
},
145 "PAG", pag_unit
, pag_reg
, NULL
,
146 2, 8, PTBL_ASIZE
, 1, 8, 32,
147 &pag_ex
, &pag_dep
, &pag_reset
,
152 /* Memory read and write routines
154 Read - read current or previous, read checking
155 ReadM - read current or previous, write checking
157 ReadP - read physical
158 Write - write current or previous
160 WriteP - write physical
161 AccChk - test accessibility of virtual address
164 d10
Read (a10 ea
, int32 prv
)
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 */
177 d10
ReadM (a10 ea
, int32 prv
)
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 */
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 */
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 */
211 void Write (a10 ea
, d10 val
, int32 prv
)
215 if (ea
< AC_NUM
) { /* AC request */
216 if (prv
) ac_prv
[ea
] = val
; /* write AC */
217 else ac_cur
[ea
] = val
;
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 */
230 void WriteE (a10 ea
, d10 val
)
234 if (ea
< AC_NUM
) AC(ea
) = val
; /* AC? use current */
235 else if (!PAGING
) M
[ea
] = val
; /* phys? no mapping */
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 */
247 void WriteP (a10 ea
, d10 val
)
249 if (ea
< AC_NUM
) AC(ea
) = val
; /* AC request */
251 if (MEM_ADDR_NXM (ea
)) pag_nxm (ea
, REF_P
, PF_TR
); /* process nxm */
252 M
[ea
] = val
; /* memory */
257 t_bool
AccViol (a10 ea
, int32 prv
, int32 mode
)
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 */
270 void pag_nxm (a10 pa
, int32 phys
, int32 trap
)
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? */
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.
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.
294 #define PAGE_FAIL_TRAP if (mode & (PTF_CON | PTF_MAP)) return 0; \
296 #define READPT(x,y) if (MEM_ADDR_NXM (y)) { \
297 pag_nxm (y, REF_P, PF_OK); \
302 int32
ptbl_fill (a10 ea
, int32
*tbl
, int32 mode
)
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.
312 ITS has no MAP instruction, therefore, physical NXM traps are ok.
315 if (Q_ITS
) { /* ITS paging */
316 int32 acc
, decvpn
, pte
, vpn
, ptead
, xpte
;
319 vpn
= ITS_GETVPN (ea
); /* get ITS pagno */
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 */
339 return (xpte
+ ((decvpn
& 1)? PAG_SIZE
: 0));
342 } /* end ITS paging */
344 /* TOPS-10 paging - checked against KS10 microcode
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
352 else if (!T20PAG
) { /* TOPS-10 paging */
353 int32 pte
, vpn
, ptead
, xpte
;
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 */
378 } /* end TOPS10 paging */
380 /* TOPS-20 paging - checked against KS10 microcode
382 TOPS-20 paging has three phases:
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.
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).
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.
398 else { /* TOPS-20 paging */
399 int32 pmi
, vpn
, xpte
;
404 d10 acc
= PTE_T20_W
| PTE_T20_C
; /* init access bits */
406 pager_word
= PF_VIRT
| ea
| ((tbl
== uptbl
)? PF_USER
: 0) |
407 ((mode
& PTF_WR
)? PF_WRITE
: 0); /* set page fail word */
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.
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.
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 */
432 case T20_NOA
: /* no access */
433 default: /* undefined type */
434 PAGE_FAIL_TRAP
; /* page fail */
436 case T20_IMM
: /* immediate */
437 stop
= TRUE
; /* exit */
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 */
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
);
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 */
462 /* Second phase - found page map ptr, evaluate page pointers */
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 */
474 READPT (ptr
, pa
& PAMASK
); /* get pointer */
475 acc
= acc
& ptr
; /* cascade acc bits */
476 switch (T20_GETTYP (ptr
)) { /* case on ptr type */
478 case T20_NOA
: /* no access */
479 default: /* undefined type */
480 PAGE_FAIL_TRAP
; /* page fail */
482 case T20_IMM
: /* immediate */
483 stop
= TRUE
; /* exit */
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 */
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 */
502 /* Last phase - have final page pointer, check modifiability */
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 */
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 */
519 else { PAGE_FAIL_TRAP
; } /* no, trap */
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 */
528 } /* end TOPS20 paging */
531 /* Set up pointers for AC, memory, and process table access */
533 void set_dyn_ptrs (void)
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];
542 ptbl_cur
= &eptbl
[0];
543 ptbl_prv
= TSTF (F_UIO
)? &uptbl
[0]: &eptbl
[0];
547 ac_cur
= ac_prv
= &acs
[0];
548 ptbl_cur
= ptbl_prv
= &physptbl
[0];
550 t
= EBR_GETEBR (ebr
);
551 epta
= t
<< PAG_V_PN
;
552 if (Q_ITS
) upta
= (int32
) ubr
& PAMASK
;
554 t
= UBR_GETUBR (ubr
);
555 upta
= t
<< PAG_V_PN
;
560 /* MAP instruction, TOPS-10 and TOPS-20 only
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
567 d10
map (a10 ea
, int32 prv
)
570 d10 val
= (TSTF (F_USR
)? PF_USER
: 0);
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
);
576 if (pager_word
& PF_HARD
) val
= pager_word
; /* hard error */
577 else val
= val
| PF_VIRT
| ea
; /* inaccessible */
582 /* Mapping routine for console */
584 a10
conmap (a10 ea
, int32 mode
, int32 sw
)
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
;
593 xpte
= ptbl_fill (ea
, tbl
, mode
);
594 if (xpte
) return PAG_XPTEPA (xpte
, ea
);
595 else return MAXMEMSIZE
;
598 /* Common pager instructions */
600 t_bool
clrpt (a10 ea
, int32 prv
)
602 int32 vpn
= PAG_GETVPN (ea
); /* get page num */
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 */
611 uptbl
[vpn
] = 0; /* clear entries in */
612 eptbl
[vpn
] = 0; /* both page tables */
617 t_bool
wrebr (a10 ea
, int32 prv
)
619 ebr
= ea
& EBR_MASK
; /* store EBR */
620 pag_reset (&pag_dev
); /* clear page tables */
621 set_dyn_ptrs (); /* set dynamic ptrs */
625 t_bool
rdebr (a10 ea
, int32 prv
)
627 Write (ea
, (ebr
& EBR_MASK
), prv
);
631 t_bool
wrubr (a10 ea
, int32 prv
)
633 d10 val
= Read (ea
, prv
);
634 d10 ubr_mask
= (Q_ITS
)? PAMASK
: UBR_UBRMASK
; /* ITS: ubr is wd addr */
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 */
642 else val
= val
& ~ubr_mask
; /* no, keep old val */
643 ubr
= (ubr
| val
) & (UBR_ACBMASK
| ubr_mask
);
648 t_bool
rdubr (a10 ea
, int32 prv
)
650 ubr
= ubr
& (UBR_ACBMASK
| (Q_ITS
? PAMASK
: UBR_UBRMASK
));
651 Write (ea
, UBRWORD
, prv
);
655 t_bool
wrhsb (a10 ea
, int32 prv
)
657 hsb
= Read (ea
, prv
) & PAMASK
;
661 t_bool
rdhsb (a10 ea
, int32 prv
)
663 Write (ea
, hsb
, prv
);
667 /* TOPS20 pager instructions */
669 t_bool
wrspb (a10 ea
, int32 prv
)
671 spt
= Read (ea
, prv
);
675 t_bool
rdspb (a10 ea
, int32 prv
)
677 Write (ea
, spt
, prv
);
681 t_bool
wrcsb (a10 ea
, int32 prv
)
683 cst
= Read (ea
, prv
);
687 t_bool
rdcsb (a10 ea
, int32 prv
)
689 Write (ea
, cst
, prv
);
693 t_bool
wrpur (a10 ea
, int32 prv
)
695 pur
= Read (ea
, prv
);
699 t_bool
rdpur (a10 ea
, int32 prv
)
701 Write (ea
, pur
, prv
);
705 t_bool
wrcstm (a10 ea
, int32 prv
)
707 cstm
= Read (ea
, prv
);
708 if ((cpu_unit
.flags
& UNIT_T20
) && (ea
== 040127))
709 cstm
= 0770000000000;
713 t_bool
rdcstm (a10 ea
, int32 prv
)
715 Write (ea
, cstm
, prv
);
719 /* ITS pager instructions
720 The KS10 does not implement the JPC option.
723 t_bool
clrcsh (a10 ea
, int32 prv
)
728 t_bool
ldbr1 (a10 ea
, int32 prv
)
731 pag_reset (&pag_dev
);
735 t_bool
sdbr1 (a10 ea
, int32 prv
)
737 Write (ea
, dbr1
, prv
);
741 t_bool
ldbr2 (a10 ea
, int32 prv
)
744 pag_reset (&pag_dev
);
748 t_bool
sdbr2 (a10 ea
, int32 prv
)
750 Write (ea
, dbr2
, prv
);
754 t_bool
ldbr3 (a10 ea
, int32 prv
)
757 pag_reset (&pag_dev
);
761 t_bool
sdbr3 (a10 ea
, int32 prv
)
763 Write (ea
, dbr3
, prv
);
767 t_bool
ldbr4 (a10 ea
, int32 prv
)
770 pag_reset (&pag_dev
);
774 t_bool
sdbr4 (a10 ea
, int32 prv
)
776 Write (ea
, dbr4
, prv
);
780 t_bool
wrpcst (a10 ea
, int32 prv
)
782 pcst
= Read (ea
, prv
);
786 t_bool
rdpcst (a10 ea
, int32 prv
)
788 Write (ea
, pcst
, prv
);
792 t_bool
lpmr (a10 ea
, int32 prv
)
796 val
= Read (ADDA (ea
, 2), prv
);
797 dbr1
= (a10
) (Read (ea
, prv
) & AMASK
);
798 dbr2
= (a10
) (Read (ADDA (ea
, 1), prv
) & AMASK
);
800 pag_reset (&pag_dev
);
804 t_bool
spm (a10 ea
, int32 prv
)
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
);
814 /* Simulator interface routines */
816 t_stat
pag_ex (t_value
*vptr
, t_addr addr
, UNIT
*uptr
, int32 sw
)
818 int32 tbln
= uptr
- pag_unit
;
820 if (addr
>= PTBL_MEMSIZE
) return SCPE_NXM
;
821 *vptr
= tbln
? uptbl
[addr
]: eptbl
[addr
];;
825 t_stat
pag_dep (t_value val
, t_addr addr
, UNIT
*uptr
, int32 sw
)
827 int32 tbln
= uptr
- pag_unit
;
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
;
835 t_stat
pag_reset (DEVICE
*dptr
)
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
;