Commit | Line | Data |
---|---|---|
196ba1fc PH |
1 | /* hp2100_cpu5.c: HP 1000 RTE-6/VM VMA and RTE-IV EMA instructions\r |
2 | \r | |
3 | Copyright (c) 2006, J. David Bryan\r | |
4 | Copyright (c) 2007-2008, Holger Veit\r | |
5 | \r | |
6 | Permission is hereby granted, free of charge, to any person obtaining a\r | |
7 | copy of this software and associated documentation files (the "Software"),\r | |
8 | to deal in the Software without restriction, including without limitation\r | |
9 | the rights to use, copy, modify, merge, publish, distribute, sublicense,\r | |
10 | and/or sell copies of the Software, and to permit persons to whom the\r | |
11 | Software is furnished to do so, subject to the following conditions:\r | |
12 | \r | |
13 | The above copyright notice and this permission notice shall be included in\r | |
14 | all copies or substantial portions of the Software.\r | |
15 | \r | |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r | |
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r | |
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\r | |
19 | THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r | |
20 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r | |
21 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r | |
22 | \r | |
23 | Except as contained in this notice, the name of the authors shall not be\r | |
24 | used in advertising or otherwise to promote the sale, use or other dealings\r | |
25 | in this Software without prior written authorization from the authors.\r | |
26 | \r | |
27 | CPU5 RTE-6/VM and RTE-IV firmware option instructions\r | |
28 | \r | |
29 | 01-May-08 HV Fixed mapping bug in "cpu_ema_emap"\r | |
30 | 21-Apr-08 JDB Added EMA support from Holger\r | |
31 | 25-Nov-07 JDB Added TF fix from Holger\r | |
32 | 07-Nov-07 HV VMACK diagnostic tests 1...32 passed\r | |
33 | 19-Oct-07 JDB Corrected $LOC operand profile to OP_CCCACC\r | |
34 | 03-Oct-07 HV Moved RTE-6/VM instrs from hp2100_cpu0.c\r | |
35 | 26-Sep-06 JDB Created\r | |
36 | \r | |
37 | Primary references:\r | |
38 | - HP 1000 M/E/F-Series Computers Technical Reference Handbook\r | |
39 | (5955-0282, Mar-1980)\r | |
40 | - HP 1000 M/E/F-Series Computers Engineering and Reference Documentation\r | |
41 | (92851-90001, Mar-1981)\r | |
42 | - Macro/1000 Reference Manual (92059-90001, Dec-1992)\r | |
43 | \r | |
44 | Additional references are listed with the associated firmware\r | |
45 | implementations, as are the HP option model numbers pertaining to the\r | |
46 | applicable CPUs.\r | |
47 | */\r | |
48 | \r | |
49 | #include <setjmp.h>\r | |
50 | #include "hp2100_defs.h"\r | |
51 | #include "hp2100_cpu.h"\r | |
52 | #include "hp2100_cpu1.h"\r | |
53 | \r | |
54 | \r | |
55 | t_stat cpu_rte_vma (uint32 IR, uint32 intrq); /* RTE-6 VMA */\r | |
56 | t_stat cpu_rte_ema (uint32 IR, uint32 intrq); /* RTE-IV EMA */\r | |
57 | \r | |
58 | \r | |
59 | /* RTE-6/VM Virtual Memory Area Instructions\r | |
60 | \r | |
61 | RTE-6/VM (product number 92084A) introduced Virtual Memory Area (VMA)\r | |
62 | instructions -- a superset of the RTE-IV EMA instructions. Different\r | |
63 | microcode was supplied with the operating system that replaced the microcode\r | |
64 | used with RTE-IV. Microcode was limited to the E/F-Series, and the M-Series\r | |
65 | used software equivalents.\r | |
66 | \r | |
67 | Option implementation by CPU was as follows:\r | |
68 | \r | |
69 | 2114 2115 2116 2100 1000-M 1000-E 1000-F\r | |
70 | ------ ------ ------ ------ ------ ------ ------\r | |
71 | N/A N/A N/A N/A N/A 92084A 92084A\r | |
72 | \r | |
73 | The routines are mapped to instruction codes as follows:\r | |
74 | \r | |
75 | Instr. 1000-E/F Description\r | |
76 | ------ -------- ----------------------------------------------\r | |
77 | .PMAP 105240 Map VMA page into map register\r | |
78 | $LOC 105241 Load on call\r | |
79 | [test] 105242 [self test]\r | |
80 | .SWP 105243 [Swap A and B registers]\r | |
81 | .STAS 105244 [STA B; LDA SP]\r | |
82 | .LDAS 105245 [LDA SP]\r | |
83 | .MYAD 105246 [NOP in microcode]\r | |
84 | .UMPY 105247 [Unsigned multiply and add]\r | |
85 | \r | |
86 | .IMAP 105250 Integer element resolve address and map\r | |
87 | .IMAR 105251 Integer element resolve address\r | |
88 | .JMAP 105252 Double integer element resolve address and map\r | |
89 | .JMAR 105253 Double integer element resolve address\r | |
90 | .LPXR 105254 Map pointer in P+1 plus offset in P+2\r | |
91 | .LPX 105255 Map pointer in A/B plus offset in P+1\r | |
92 | .LBPR 105256 Map pointer in P+1\r | |
93 | .LBP 105257 Map pointer in A/B registers\r | |
94 | \r | |
95 | Notes:\r | |
96 | \r | |
97 | 1. The opcodes 105243-247 are undocumented and do not appear to be used in\r | |
98 | any HP software.\r | |
99 | \r | |
100 | 2. The opcode list in the CE Handbook incorrectly shows 105246 as ".MYAD -\r | |
101 | multiply 2 signed integers." The microcode listing shows that this\r | |
102 | instruction was deleted, and the opcode is now a NOP.\r | |
103 | \r | |
104 | 3. RTE-IV EMA and RTE-6 VMA instructions shared the same address space, so\r | |
105 | a given machine could run one or the other, but not both.\r | |
106 | \r | |
107 | Additional references:\r | |
108 | - RTE-6/VM VMA/EMA Microcode Source (92084-18828, revision 3).\r | |
109 | - RTE-6/VM Technical Specifications (92084-90015, Apr-1983).\r | |
110 | - M/E/F-Series Computer Systems CE Handbook (5950-3767, Jul-1984).\r | |
111 | */\r | |
112 | \r | |
113 | static const OP_PAT op_vma[16] = {\r | |
114 | OP_N, OP_CCCACC, OP_N, OP_N, /* .PMAP $LOC [test] .SWAP */\r | |
115 | OP_N, OP_N, OP_N, OP_K, /* .STAS .LDAS .MYAD .UMPY */\r | |
116 | OP_A, OP_A, OP_A, OP_A, /* .IMAP .IMAR .JMAP .JMAR */\r | |
117 | OP_AA, OP_A, OP_A, OP_N /* .LPXR .LPX .LBPR .LBP */\r | |
118 | };\r | |
119 | \r | |
120 | /* some addresses in page0 of RTE-6/VM */\r | |
121 | static const uint32 idx = 0001645;\r | |
122 | static const uint32 xmata = 0001646;\r | |
123 | static const uint32 xi = 0001647;\r | |
124 | static const uint32 xeqt = 0001717;\r | |
125 | static const uint32 vswp = 0001776;\r | |
126 | static const uint32 umaps = 0003740;\r | |
127 | static const uint32 page30 = 0074000;\r | |
128 | static const uint32 page31 = 0076000;\r | |
129 | static const uint32 ptemiss = 0176000;\r | |
130 | \r | |
131 | /* frequent constants in paging */\r | |
132 | #define SUITMASK 0176000 \r | |
133 | #define NILPAGE 0176000\r | |
134 | #define PAGEIDX 0001777\r | |
135 | #define MSEGMASK 0076000\r | |
136 | #define RWPROT 0141777\r | |
137 | \r | |
138 | /* from scp.c */\r | |
139 | extern int32 sim_step;\r | |
140 | extern FILE* sim_log;\r | |
141 | \r | |
142 | /* MP abort handler */\r | |
143 | extern jmp_buf save_env;\r | |
144 | #define ABORT(val) longjmp (save_env, (val))\r | |
145 | \r | |
146 | /* microcode version of resolve(): allows a much higher # of indirection levels. Used for\r | |
147 | instance for LBP microcode diagnostics which will check > 100 levels.\r | |
148 | */ \r | |
149 | #define VMA_INDMAX 200\r | |
150 | \r | |
151 | static t_stat vma_resolve (uint32 MA, uint32 *addr, t_bool debug)\r | |
152 | {\r | |
153 | uint32 i;\r | |
154 | uint32 faultma = MA;\r | |
155 | \r | |
156 | for (i = 0; (i < VMA_INDMAX) && (MA & I_IA); i++) { /* resolve multilevel */\r | |
157 | MA = ReadW (MA & VAMASK); /* follow address chain */\r | |
158 | } \r | |
159 | \r | |
160 | if (MA & I_IA) {\r | |
161 | if (debug)\r | |
162 | fprintf(sim_deb,">>CPU VMA: vma_resolve indirect loop addr=%06o\n",faultma);\r | |
163 | return STOP_IND; /* indirect loop */\r | |
164 | }\r | |
165 | \r | |
166 | *addr = MA;\r | |
167 | return SCPE_OK;\r | |
168 | }\r | |
169 | \r | |
170 | /* $LOC\r | |
171 | ASSEMBLER CALLING SEQUENCE:\r | |
172 | \r | |
173 | $MTHK NOP RETURN ADDRESS OF CALL (REDONE AFTER THIS ROUTINE)\r | |
174 | JSB $LOC\r | |
175 | .DTAB OCT LGPG# LOGICAL PAGE # AT WHICH THE NODE TO \r | |
176 | * BE MAPPED IN BELONGS (0-31)\r | |
177 | OCT RELPG RELATIVE PAGE OFFSET FROM BEGINING\r | |
178 | * OF PARTITION OF WHERE THAT NODE RESIDES.\r | |
179 | * (0 - 1023)\r | |
180 | OCT RELBP RELATIVE PAGE OFFSET FROM BEGINING OF \r | |
181 | * PARTITION OF WHERE BASE PAGE RESIDES\r | |
182 | * (0 - 1023)\r | |
183 | CNODE DEF .CNOD THIS IS THE ADDRESS OF CURRENT PATH # WORD\r | |
184 | .ORD OCT XXXXX THIS NODE'S LEAF # (IE PATH #)\r | |
185 | .NOD# OCT XXXXX THIS NODE'S ORDINAL # \r | |
186 | */\r | |
187 | \r | |
188 | static t_stat cpu_vma_loc(OPS op,uint32 intrq,t_bool debug)\r | |
189 | {\r | |
190 | uint32 eqt,mls,pnod,lstpg,fstpg,rotsz,lgpg,relpg,relbp,matloc,ptnpg,physpg,cnt,pgs,umapr;\r | |
191 | \r | |
192 | eqt = ReadIO(xeqt,UMAP); /* get ID segment */\r | |
193 | mls = ReadIO(eqt+33,SMAP); /* get word33 of alternate map */\r | |
194 | if ((mls & 0x8000) == 0) { /* this is not an MLS prog! */\r | |
195 | PC = err_PC;\r | |
196 | if (debug)\r | |
197 | fprintf(sim_deb,">>CPU VMA: cpu_vma_loc at P=%06o: not an MLS program\n", PC);\r | |
198 | if (CTL (PRO)) ABORT (ABORT_PRO); /* allow an MP abort */\r | |
199 | return STOP_HALT; /* FATAL error! */\r | |
200 | }\r | |
201 | \r | |
202 | pnod = mls & 01777; /* get #pages of mem res nodes */\r | |
203 | if (pnod == 0) { /* no pages? FATAL! */\r | |
204 | PC = err_PC;\r | |
205 | if (debug)\r | |
206 | fprintf(sim_deb,">>CPU VMA: cpu_vma_loc at P=%06o: no mem resident pages\n", PC);\r | |
207 | if (CTL (PRO)) ABORT (ABORT_PRO); /* allow an MP abort */\r | |
208 | return STOP_HALT;\r | |
209 | }\r | |
210 | \r | |
211 | lstpg = (ReadIO(eqt+29,SMAP) >> 10) - 1; /* last page# of code */\r | |
212 | fstpg = ReadIO(eqt+23,SMAP) >> 10; /* index to 1st addr + mem nodes */\r | |
213 | rotsz = fstpg - (ReadIO(eqt+22,SMAP) >> 10); /* #pages in root */\r | |
214 | lgpg = op[0].word;\r | |
215 | \r | |
216 | /* lets do some consistency checks, CPU halt if they fail */\r | |
217 | if (lstpg < lgpg || lgpg < fstpg) { /* assert LSTPG >= LGPG# >= FSTPG */\r | |
218 | PC = err_PC;\r | |
219 | if (debug) \r | |
220 | fprintf(sim_deb,\r | |
221 | ">>CPU VMA: $LOC at P=%06o: failed check LSTPG >= LGPG# >= FSTPG\n",PC);\r | |
222 | if (CTL (PRO)) ABORT (ABORT_PRO); /* allow an MP abort */\r | |
223 | return STOP_HALT;\r | |
224 | }\r | |
225 | \r | |
226 | relpg = op[1].word;\r | |
227 | if (pnod < relpg || relpg < (rotsz+1)) { /* assert #PNOD >= RELPG >= ROTSZ+1 */\r | |
228 | PC = err_PC;\r | |
229 | if (debug) \r | |
230 | fprintf(sim_deb,\r | |
231 | ">>CPU VMA: $LOC at %06o: failed check #PNOD >= RELPG >= ROTSZ+1\n",PC);\r | |
232 | if (CTL (PRO)) ABORT (ABORT_PRO); /* allow an MP abort */\r | |
233 | return STOP_HALT;\r | |
234 | }\r | |
235 | \r | |
236 | relbp = op[2].word;\r | |
237 | if (relbp != 0) /* assert RELBP == 0 OR */\r | |
238 | if (pnod < relbp || relbp < (rotsz+1)) { /* #PNOD >= RELBP >= ROTSZ+1 */\r | |
239 | PC = err_PC;\r | |
240 | if (debug) \r | |
241 | fprintf(sim_deb,\r | |
242 | ">>CPU VMA: $LOC at P=%06o: failed check: #PNOD >= RELBP >= ROTSZ+1\n",PC);\r | |
243 | if (CTL (PRO)) ABORT (ABORT_PRO); /* allow an MP abort */\r | |
244 | return STOP_HALT;\r | |
245 | }\r | |
246 | \r | |
247 | cnt = lstpg - lgpg + 1; /* #pages to map */\r | |
248 | pgs = pnod - relpg + 1; /* #pages from start node to end of code */\r | |
249 | if (pgs < cnt) cnt = pgs; /* ensure minimum, so not to map into EMA */\r | |
250 | \r | |
251 | matloc = ReadIO(xmata,UMAP); /* get MAT $LOC address */\r | |
252 | ptnpg = ReadIO(matloc+3,SMAP) & 01777; /* index to start phys pg */\r | |
253 | physpg = ptnpg + relpg; /* phys pg # of node */\r | |
254 | umapr = 32 + lgpg; /* map register to start */\r | |
255 | \r | |
256 | /* do an XMS with AR=umapr,BR=physpg,XR=cnt */\r | |
257 | if (debug)\r | |
258 | fprintf(sim_deb,\r | |
259 | ">>CPU VMA: $LOC map %d pgs from phys=%06o to mapr=%d\n",\r | |
260 | cnt,physpg,umapr);\r | |
261 | while (cnt != 0) {\r | |
262 | dms_wmap (umapr, physpg); /* map pages of new overlay segment */\r | |
263 | cnt = (cnt - 1) & DMASK;\r | |
264 | umapr = (umapr + 1) & DMASK;\r | |
265 | physpg = (physpg + 1) & DMASK;\r | |
266 | }\r | |
267 | \r | |
268 | dms_wmap(32,relbp+ptnpg); /* map base page again */\r | |
269 | WriteW(op[3].word,op[4].word); /* path# we are going to */\r | |
270 | \r | |
271 | PC = (PC - 8) & DMASK; /* adjust PC to return address */\r | |
272 | /* word before the $LOC microinstr. */\r | |
273 | PC = (ReadW(PC) - 1) & DMASK; /* but the call has to be rerun, */\r | |
274 | /* so must skip back to the original call */\r | |
275 | /* which will now lead to the real routine */\r | |
276 | if (debug)\r | |
277 | fprintf(sim_deb,">>CPU VMA: $LOC done: path#=%06o, P=%06o\n",op[4].word,PC);\r | |
278 | return SCPE_OK;\r | |
279 | }\r | |
280 | \r | |
281 | /* map pte into last page\r | |
282 | return FALSE if page fault, nil flag in PTE or suit mismatch \r | |
283 | return TRUE if suit match, physpg = physical page \r | |
284 | or page=0 -> last+1 page\r | |
285 | */\r | |
286 | static t_bool cpu_vma_ptevl(uint32 pagid,uint32* physpg)\r | |
287 | {\r | |
288 | uint32 suit;\r | |
289 | uint32 pteidx = pagid & 0001777; /* build index */\r | |
290 | uint32 reqst = pagid & SUITMASK; /* required suit */\r | |
291 | uint32 pteval = ReadW(page31 | pteidx); /* get PTE entry */\r | |
292 | *physpg = pteval & 0001777; /* store physical page number */\r | |
293 | suit = pteval & SUITMASK; /* suit number seen */\r | |
294 | if (pteval == NILPAGE) return FALSE; /* NIL value in PTE */\r | |
295 | return suit == reqst || !*physpg; /* good page or last+1 */\r | |
296 | }\r | |
297 | \r | |
298 | /* handle page fault */\r | |
299 | static t_stat cpu_vma_fault(uint32 x,uint32 y,int32 mapr,\r | |
300 | uint32 ptepg,uint32 ptr,uint32 faultpc, t_bool debug)\r | |
301 | {\r | |
302 | uint32 pre = ReadIO(xi,UMAP); /* get program preamble */\r | |
303 | uint32 ema = ReadIO(pre+2,UMAP); /* get address of $EMA$/$VMA$ */\r | |
304 | WriteIO(ema,faultpc,UMAP); /* write addr of fault instr */\r | |
305 | XR = x; /* X = faulting page */\r | |
306 | YR = y; /* Y = faulting address for page */\r | |
307 | \r | |
308 | if (mapr>0)\r | |
309 | dms_wmap(mapr+UMAP,ptepg); /* map PTE into specified user dmsmap */\r | |
310 | \r | |
311 | /* do a safety check: first instr of $EMA$/$VMA$ must be a DST instr */\r | |
312 | if (ReadIO(ema+1,UMAP) != 0104400) {\r | |
313 | if (debug) \r | |
314 | fprintf(sim_deb, ">>CPU VMA: pg fault: no EMA/VMA user code present\n");\r | |
315 | if (CTL (PRO)) ABORT (ABORT_PRO); /* allow an MP abort */\r | |
316 | return STOP_HALT; /* FATAL: no EMA/VMA! */\r | |
317 | }\r | |
318 | \r | |
319 | PC = (ema+1) & VAMASK; /* restart $EMA$ user code, */\r | |
320 | /* will return to fault instruction */\r | |
321 | \r | |
322 | AR = (ptr >> 16) & DMASK; /* restore A, B */\r | |
323 | BR = ptr & DMASK;\r | |
324 | E = 0; /* enforce E = 0 */\r | |
325 | if (debug)\r | |
326 | fprintf(sim_deb, \r | |
327 | ">>CPU VMA: Call pg fault OS exit, AR=%06o BR=%06o P=%06o\n",\r | |
328 | AR, BR, PC);\r | |
329 | return SCPE_OK;\r | |
330 | }\r | |
331 | \r | |
332 | /* map in PTE into last page, return false, if page fault */\r | |
333 | static t_bool cpu_vma_mapte(uint32* ptepg)\r | |
334 | {\r | |
335 | uint32 idext,idext2;\r | |
336 | uint32 dispatch = ReadIO(vswp,UMAP) & 01777; /* get fresh dispatch flag */\r | |
337 | t_bool swapflag = TRUE;\r | |
338 | \r | |
339 | if (dispatch == 0) { /* not yet set */\r | |
340 | idext = ReadIO(idx,UMAP); /* go into IDsegment extent */\r | |
341 | if (idext != 0) { /* is ema/vma program? */\r | |
342 | dispatch = ReadWA(idext+1) & 01777; /* get 1st ema page: new vswp */\r | |
343 | WriteIO(vswp,dispatch,UMAP); /* move into $VSWP */\r | |
344 | idext2 = ReadWA(idext+2); /* get swap bit */\r | |
345 | swapflag = (idext2 & 020000) != 0; /* bit 13 = swap bit */\r | |
346 | }\r | |
347 | }\r | |
348 | \r | |
349 | if (dispatch) { /* some page is defined */\r | |
350 | dms_wmap(31 + UMAP,dispatch); /* map $VSWP to register 31 */\r | |
351 | *ptepg = dispatch; /* return PTEPG# for later */\r | |
352 | }\r | |
353 | \r | |
354 | return swapflag; /* true for swap bit set */\r | |
355 | }\r | |
356 | \r | |
357 | /* .LBP\r | |
358 | ASSEMBLER CALLING SEQUENCE:\r | |
359 | \r | |
360 | DLD PONTR TRANSLATE 32 BIT POINTER TO 15\r | |
361 | JSB .LBP BIT POINTER.\r | |
362 | <RETURN - B = LOGICAL ADDRESS, A = PAGID> \r | |
363 | \r | |
364 | 32 bit pointer:\r | |
365 | ----------AR------------ -----BR-----\r | |
366 | 15 14....10 9....4 3...0 15.10 9....0\r | |
367 | L<----------------------------------- L=1 local reference bit\r | |
368 | XXXXXXXX<------------------------- 5 bit unused\r | |
369 | PPPPPP PPPPP PPPPP<------ 16 bit PAGEID\r | |
370 | SSSSSS<------------------ SUIT# within PAGEID\r | |
371 | PPPPP PPPPP<------ 10 bit PAGEID index into PTE\r | |
372 | OOOOOO 10 bit OFFSET\r | |
373 | */\r | |
374 | \r | |
375 | static t_stat cpu_vma_lbp(uint32 ptr,uint32 aoffset,uint32 faultpc,uint32 intrq,t_bool debug) \r | |
376 | {\r | |
377 | uint32 pagid,offset,ptrl,pgidx,ptepg;\r | |
378 | uint16 p30,p31,suit;\r | |
379 | t_stat reason = SCPE_OK;\r | |
380 | uint32 faultab = ptr; /* remember A,B for page fault */\r | |
381 | ptr += aoffset; /* add the offset e.g. for .LPX */\r | |
382 | \r | |
383 | if (debug)\r | |
384 | fprintf(sim_deb,">>CPU VMA: cpu_vma_lbp: ptr=%o/%o\n",\r | |
385 | (ptr>>16) & DMASK,ptr & DMASK);\r | |
386 | \r | |
387 | O = 0; /* clear overflow */\r | |
388 | if (ptr & 0x80000000) { /* is it a local reference? */\r | |
389 | ptrl = ptr & VAMASK;\r | |
390 | if ((ptr&I_IA) && (reason = vma_resolve (ReadW (ptrl), &ptrl, debug)))\r | |
391 | return reason; /* yes, resolve indirect ref */\r | |
392 | BR = ptrl & VAMASK; /* address is local */\r | |
393 | AR = (ptr >> 16) & DMASK; \r | |
394 | if (debug)\r | |
395 | fprintf(sim_deb,">>CPU VMA: cpu_vma_lbp: local ref AR=%06o BR=%06o\n",AR,BR);\r | |
396 | return SCPE_OK;\r | |
397 | }\r | |
398 | \r | |
399 | pagid = (ptr >> 10) & DMASK; /* extract page id (16 bit idx, incl suit*/\r | |
400 | offset = ptr & 01777; /* and offset */\r | |
401 | suit = pagid & SUITMASK; /* suit of page */\r | |
402 | pgidx = pagid & PAGEIDX; /* index into PTE */\r | |
403 | \r | |
404 | if (!cpu_vma_mapte(&ptepg)) /* map in PTE */\r | |
405 | return cpu_vma_fault(65535,ptemiss,-1,ptepg,faultab,faultpc, debug); /* oops, must init PTE */\r | |
406 | \r | |
407 | /* ok, we have the PTE mapped to page31 */\r | |
408 | /* the microcode tries to reads two consecutive data pages into page30 and page31 */\r | |
409 | \r | |
410 | /* read the 1st page value from PTE */\r | |
411 | p30 = ReadW(page31 | pgidx) ^ suit;\r | |
412 | if (!p30) /* matched suit for 1st page */\r | |
413 | return cpu_vma_fault(pagid,page30,30,ptepg,faultab,faultpc,debug);\r | |
414 | \r | |
415 | /* suit switch situation: 1st page is in last idx of PTE, then following page\r | |
416 | * must be in idx 0 of PTE */\r | |
417 | if (pgidx==01777) { /* suit switch situation */\r | |
418 | pgidx = 0; /* select correct idx 0 */\r | |
419 | suit = pagid+1; /* suit needs increment */\r | |
420 | if (suit==0) { /* is it page 65536? */\r | |
421 | offset += 02000; /* adjust to 2nd page */\r | |
422 | suit = NILPAGE;\r | |
423 | pgidx = 01777;\r | |
424 | }\r | |
425 | } else\r | |
426 | pgidx++; /* select next page */\r | |
427 | \r | |
428 | p31 = ReadW(page31 | pgidx) ^ suit;\r | |
429 | if (!p31) { /* matched suit for 2nd page */\r | |
430 | dms_wmap(31+UMAP,p30);\r | |
431 | if (p30 & SUITMASK)\r | |
432 | return cpu_vma_fault(pagid,page30,30,ptepg,faultab,faultpc,debug);\r | |
433 | if (!(p31 ^ NILPAGE)) /* suit is 63: fault */\r | |
434 | return cpu_vma_fault(pagid+1,page31,31,ptepg,faultab,faultpc,debug);\r | |
435 | \r | |
436 | offset += 02000; /* adjust offset to last user map because */\r | |
437 | /* the address requested page 76xxx */\r | |
438 | } \r | |
439 | else {\r | |
440 | dms_wmap(30+UMAP,p30);\r | |
441 | if (p30 & SUITMASK)\r | |
442 | return cpu_vma_fault(pagid,page30,30,ptepg,faultab,faultpc,debug);\r | |
443 | dms_wmap(31+UMAP,p31);\r | |
444 | if (p31 & SUITMASK)\r | |
445 | return cpu_vma_fault(pagid+1,page31,31,ptepg,faultab,faultpc,debug);\r | |
446 | }\r | |
447 | \r | |
448 | AR = pagid; /* return pagid in A */\r | |
449 | BR = page30+offset; /* mapped address in B */\r | |
450 | if (debug)\r | |
451 | fprintf(sim_deb,">>CPU VMA: cpu_vma_lbp: map done AR=%06o BR=%o6o\n",AR,BR);\r | |
452 | return SCPE_OK;\r | |
453 | }\r | |
454 | \r | |
455 | /* .PMAP\r | |
456 | ASSEMBLER CALLING SEQUENCE:\r | |
457 | \r | |
458 | LDA UMAPR (MSEG - 31) \r | |
459 | LDB PAGID (0-65535) \r | |
460 | JSB .PMAP GO MAP IT IN\r | |
461 | <ERROR RETURN> A-REG = REASON, NOTE 1\r | |
462 | <RETURN A=A+1, B=B+1,E=0 >> SEE NOTE 2>\r | |
463 | \r | |
464 | NOTE 1 : IF BIT 15 OF A-REG SET, THEN ALL NORMAL BRANCHES TO THE \r | |
465 | $EMA$/$VMA$ CODE WILL BE CHANGED TO P+1 EXIT. THE A-REG \r | |
466 | WILL BE THE REASON THE MAPPING WAS NOT SUCCESSFUL IF BIT 15\r | |
467 | OF THE A-REG WAS NOT SET.\r | |
468 | THIS WAS DONE SO THAT A ROUTINE ($VMA$) CAN DO A MAPPING \r | |
469 | WITHOUT THE POSSIBILITY OF BEING RE-CURRED. IT IS USED\r | |
470 | BY $VMA$ AND PSTVM IN THE PRIVLEDGED MODE. \r | |
471 | NOTE 2: E-REG WILL = 1 IF THE LAST+1 PAGE IS REQUESTED AND \r | |
472 | MAPPED READ/WRITE PROTECTED ON A GOOD P+2 RETURN.\r | |
473 | */\r | |
474 | static t_stat cpu_vma_pmap(uint32 umapr,uint32 pagid, t_bool debug)\r | |
475 | {\r | |
476 | uint32 physpg, ptr, pgpte;\r | |
477 | uint32 mapnm = umapr & 0x7fff; /* strip off bit 15 */\r | |
478 | \r | |
479 | if (debug)\r | |
480 | fprintf(sim_deb, ">>CPU VMA: .PMAP AR=%06o(umapr) BR=%06o(pagid)\n",umapr,pagid);\r | |
481 | \r | |
482 | if (mapnm > 31) { /* check for invalid map register */\r | |
483 | AR = 80; /* error: corrupt EMA/VMA system */\r | |
484 | if (debug)\r | |
485 | fprintf(sim_deb, ">>CPU VMA: .PMAP invalid mapr: AR=80, exit P+1\n");\r | |
486 | return SCPE_OK; /* return exit PC+1 */\r | |
487 | }\r | |
488 | \r | |
489 | ptr = (umapr << 16) | (pagid & DMASK); /* build the ptr argument for vma_fault */ \r | |
490 | if (!cpu_vma_mapte(&pgpte)) { /* map the PTE */\r | |
491 | if (umapr & 0x8000) {\r | |
492 | XR = 65535;\r | |
493 | YR = ptemiss;\r | |
494 | if (debug)\r | |
495 | fprintf(sim_deb, \r | |
496 | ">>CPU VMA: .PMAP pg fault&bit15: XR=%06o YR=%06o, exit P+1\n",\r | |
497 | XR, YR);\r | |
498 | return SCPE_OK; /* use PC+1 error exit */\r | |
499 | }\r | |
500 | return cpu_vma_fault(65535,ptemiss,-1,pgpte,ptr,PC-1,debug); /* oops: fix PTE */\r | |
501 | }\r | |
502 | \r | |
503 | /* PTE is successfully mapped to page31 and dmsmap[63] */\r | |
504 | if (!cpu_vma_ptevl(pagid,&physpg)) {\r | |
505 | if (umapr & 0x8000) {\r | |
506 | XR = pagid;\r | |
507 | YR = page31;\r | |
508 | if (debug)\r | |
509 | fprintf(sim_deb, \r | |
510 | ">>CPU VMA: .PMAP pg map&bit15: XR=%06o YR=%06o, exit P+1\n",\r | |
511 | XR, YR);\r | |
512 | return SCPE_OK; /* use PC+1 error exit*/\r | |
513 | }\r | |
514 | return cpu_vma_fault(pagid,page31,31,pgpte,ptr,PC-1,debug); /* page not present */\r | |
515 | }\r | |
516 | \r | |
517 | E = 1;\r | |
518 | if (physpg == 0) /* last+1 page ? */\r | |
519 | physpg = RWPROT; /* yes, use page 1023 RW/Protected */\r | |
520 | else E = 0; /* normal page to map */\r | |
521 | \r | |
522 | dms_wmap(mapnm+UMAP,physpg); /* map page to user page reg */ \r | |
523 | if (mapnm != 31) /* unless already unmapped, */\r | |
524 | dms_wmap(31+UMAP,RWPROT); /* unmap PTE */\r | |
525 | \r | |
526 | AR = (umapr + 1) & DMASK; /* increment mapr for next call */\r | |
527 | BR = (pagid + 1) & DMASK; /* increment pagid for next call */\r | |
528 | O = 0; /* clear overflow */\r | |
529 | PC = (PC + 1) & VAMASK; /* normal PC+2 return */\r | |
530 | if (debug)\r | |
531 | fprintf(sim_deb,">>CPU VMA: .PMAP map done: AR=%06o BR=%o6o exit P+2\n",AR,BR);\r | |
532 | return SCPE_OK;\r | |
533 | }\r | |
534 | \r | |
535 | /* array calc helper for .imar, .jmar, .imap, .jmap\r | |
536 | ij=in_s: 16 bit descriptors\r | |
537 | ij=in_d: 32 bit descriptors\r | |
538 | \r | |
539 | This helper expects mainly the following arguments:\r | |
540 | dtbl: pointer to an array descriptor table\r | |
541 | atbl: pointer to the table of actual subscripts\r | |
542 | \r | |
543 | where subscript table is the following:\r | |
544 | atbl-> DEF last_subscript,I (point to single or double integer)\r | |
545 | ...\r | |
546 | DEF first subscript,I (point to single or double integer)\r | |
547 | \r | |
548 | where Descriptor_table is the following table: \r | |
549 | dtbl-> DEC #dimensions\r | |
550 | DEC/DIN next-to-last dimension (single or double integer)\r | |
551 | ...\r | |
552 | DEC/DIN first dimension (single or double integer)\r | |
553 | DEC elementsize in words\r | |
554 | DEC high,low offset from start of EMA to element(0,0...0)\r | |
555 | \r | |
556 | Note that subscripts are counting from 0\r | |
557 | */\r | |
558 | static t_stat cpu_vma_ijmar(OPSIZE ij,uint32 dtbl,uint32 atbl,uint32* dimret,\r | |
559 | uint32 intrq,t_bool debug)\r | |
560 | {\r | |
561 | t_stat reason = SCPE_OK;\r | |
562 | uint32 ndim,MA,i,ws;\r | |
563 | int32 accu,ax,dx;\r | |
564 | OP din;\r | |
565 | int opsz = ij==in_d ? 2 : 1;\r | |
566 | \r | |
567 | ndim = ReadW(dtbl++); /* get #dimensions itself */\r | |
568 | if (debug) {\r | |
569 | fprintf(sim_deb, ">>CPU VMA array calc #dim=%d, size=%d\n",ndim,opsz);\r | |
570 | fprintf(sim_deb, ">>CPU VMA: array actual subscripts (");\r | |
571 | for (i=0; i<ndim; i++) {\r | |
572 | MA = ReadW(atbl+i);\r | |
573 | if (resolve (MA, &MA, intrq)) break;\r | |
574 | din = ReadOp(MA,ij);\r | |
575 | if (i>0) fputc(',',sim_deb);\r | |
576 | fprintf(sim_deb,"%d",ij==in_d?INT32(din.dword) : INT16(din.word));\r | |
577 | }\r | |
578 | \r | |
579 | fprintf(sim_deb,")\n>>CPU VMA: array descriptor table (");\r | |
580 | if (ndim) {\r | |
581 | for (i=0; i<ndim-1; i++) {\r | |
582 | din = ReadOp(dtbl+i*opsz,ij);\r | |
583 | if (i>0) fputc(',',sim_deb);\r | |
584 | fprintf(sim_deb,"%d",ij==in_d?INT32(din.dword) : INT16(din.word));\r | |
585 | }\r | |
586 | i = dtbl+1+(ndim-1)*opsz;\r | |
587 | ws = ReadW(i-1);\r | |
588 | }\r | |
589 | else {\r | |
590 | i = dtbl;\r | |
591 | ws = 1;\r | |
592 | }\r | |
593 | fprintf(sim_deb,")\n>>CPU VMA: array elemsz=%d base=%o/%o\n",\r | |
594 | ws,ReadW(i),ReadW(i+1));\r | |
595 | }\r | |
596 | \r | |
597 | if (dimret) *dimret = ndim; /* return dimensions */\r | |
598 | if (ndim == 0) { /* no dimensions: */\r | |
599 | AR = ReadW(dtbl++); /* return the array base itself */\r | |
600 | BR = ReadW(dtbl);\r | |
601 | if (debug)\r | |
602 | fprintf(sim_deb,">>CPU VMA: #dim=0, AR=%06o, BR=%06o\n",AR,BR);\r | |
603 | return SCPE_OK;\r | |
604 | }\r | |
605 | \r | |
606 | /* calculate\r | |
607 | * (...(An*Dn-1)+An-1)*Dn-2)+An-2....)+A2)*D1)+A1)*#words + Array base\r | |
608 | * Depending on ij, Ax and Dx can be 16 or 32 bit\r | |
609 | */\r | |
610 | accu = 0;\r | |
611 | while (ndim-- > 0) {\r | |
612 | MA = ReadW(atbl++); /* get addr of subscript */\r | |
613 | if ((reason = resolve (MA, &MA, intrq))) /* and resolve it */\r | |
614 | return reason;\r | |
615 | din = ReadOp(MA,ij); /* get actual subscript value */\r | |
616 | ax = ij==in_d ? INT32(din.dword) : INT16(din.word);\r | |
617 | accu += ax; /* add to accu */\r | |
618 | \r | |
619 | if (ndim==0) ij = in_s; /* #words is single */\r | |
620 | din = ReadOp(dtbl,ij); /* get dimension from descriptor table */\r | |
621 | if (ij==in_d) {\r | |
622 | dx = INT32(din.dword); /* either get double or single dimension */\r | |
623 | dtbl += 2;\r | |
624 | } else {\r | |
625 | dx = INT16(din.word);\r | |
626 | dtbl++;\r | |
627 | }\r | |
628 | accu *= dx; /* multiply */\r | |
629 | } \r | |
630 | \r | |
631 | din = ReadOp(dtbl,in_d); /* add base address */\r | |
632 | accu += din.dword;\r | |
633 | \r | |
634 | AR = (accu >> 16) & DMASK; /* transfer to AB */\r | |
635 | BR = accu & DMASK;\r | |
636 | if (debug)\r | |
637 | fprintf(sim_deb,">>CPU VMA: resulting virt addr=%o (AR=%06o, BR=%06o)\n",accu,AR,BR);\r | |
638 | return reason;\r | |
639 | }\r | |
640 | \r | |
641 | /*\r | |
642 | * This is the main handler for the RTE6/VMA microcodes */\r | |
643 | t_stat cpu_rte_vma (uint32 IR, uint32 intrq)\r | |
644 | {\r | |
645 | t_stat reason = SCPE_OK;\r | |
646 | OPS op;\r | |
647 | OP_PAT pattern;\r | |
648 | uint32 entry,t32,ndim;\r | |
649 | uint32 dtbl,atbl; /* descriptor table ptr, actual args ptr */\r | |
650 | OP dop0,dop1;\r | |
651 | uint32 pcsave = (PC+1) & VAMASK; /* save PC to check for redo in imap/jmap */\r | |
652 | t_bool debug = DEBUG_PRI (cpu_dev, DEB_VMA);\r | |
653 | \r | |
654 | if ((cpu_unit.flags & UNIT_VMAOS) == 0) /* VMA/OS option installed? */\r | |
655 | return cpu_rte_ema (IR, intrq); /* try EMA */\r | |
656 | \r | |
657 | entry = IR & 017; /* mask to entry point */\r | |
658 | pattern = op_vma[entry]; /* get operand pattern */\r | |
659 | \r | |
660 | if (pattern != OP_N)\r | |
661 | if (reason = cpu_ops (pattern, op, intrq)) /* get instruction operands */\r | |
662 | return reason;\r | |
663 | \r | |
664 | if (debug) { /* debugging? */\r | |
665 | fprintf (sim_deb, ">>CPU VMA: IR = %06o (", IR); /* print preamble and IR */\r | |
666 | fprint_sym (sim_deb, err_PC, (t_value *) &IR, /* print instruction mnemonic */\r | |
667 | NULL, SWMASK('M'));\r | |
668 | fprintf (sim_deb, "), P = %06o, XEQT = %06o", /* print location and program ID */\r | |
669 | err_PC, ReadW (xeqt));\r | |
670 | \r | |
671 | fprint_ops (pattern, op); /* print operands */\r | |
672 | fputc ('\n', sim_deb); /* terminate line */\r | |
673 | }\r | |
674 | \r | |
675 | switch (entry) { /* decode IR<3:0> */\r | |
676 | \r | |
677 | case 000: /* .PMAP 105240 (OP_N) */\r | |
678 | reason = cpu_vma_pmap(AR,BR,debug); /* map pages */\r | |
679 | break;\r | |
680 | \r | |
681 | case 001: /* $LOC 105241 (OP_CCCACC) */\r | |
682 | reason = cpu_vma_loc(op,intrq,debug); /* handle the coroutine switch */\r | |
683 | break;\r | |
684 | \r | |
685 | case 002: /* [test] 105242 (OP_N) */\r | |
686 | XR = 3; /* refer to src code 92084-18828 rev 3 */\r | |
687 | SR = 0102077; /* HLT 77 instruction */\r | |
688 | YR = 1; /* ROMs correctly installed */\r | |
689 | PC = (PC+1) & VAMASK; /* skip instr if VMA/EMA ROM installed */\r | |
690 | break;\r | |
691 | \r | |
692 | case 003: /* [swap] 105243 (OP_N) */\r | |
693 | t32 = AR; /* swap A and B registers */\r | |
694 | AR = BR;\r | |
695 | BR = t32;\r | |
696 | break;\r | |
697 | \r | |
698 | case 004: /* [---] 105244 (OP_N) */\r | |
699 | reason = stop_inst; /* fragment of dead code */\r | |
700 | break; /* in microrom */\r | |
701 | \r | |
702 | case 005: /* [---] 105245 (OP_N) */\r | |
703 | reason = stop_inst; /* fragment of dead code */\r | |
704 | break; /* in microrom */\r | |
705 | \r | |
706 | case 006: /* [nop] 105246 (OP_N) */\r | |
707 | break; /* do nothing */\r | |
708 | \r | |
709 | case 007: /* [umpy] 105247 (OP_K) */\r | |
710 | t32 = AR * op[0].word; /* get multiplier */\r | |
711 | t32 += BR; /* add B */\r | |
712 | AR = (t32 >> 16) & DMASK; /* move result back to AB */\r | |
713 | BR = t32 & DMASK;\r | |
714 | O = 0; /* instr clears OV */\r | |
715 | break;\r | |
716 | \r | |
717 | case 010: /* .IMAP 105250 (OP_A) */\r | |
718 | dtbl = op[0].word; \r | |
719 | atbl = PC;\r | |
720 | if ((reason = cpu_vma_ijmar(in_s,dtbl,atbl,&ndim,intrq,debug))) /* calc the virt address to AB */\r | |
721 | return reason;\r | |
722 | t32 = (AR << 16) | (BR & DMASK);\r | |
723 | if ((reason = cpu_vma_lbp(t32,0,PC-2,intrq,debug)))\r | |
724 | return reason;\r | |
725 | if (PC==pcsave) \r | |
726 | PC = (PC+ndim) & VAMASK; /* adjust PC: skip ndim subscript words */\r | |
727 | break;\r | |
728 | \r | |
729 | case 011: /* .IMAR 105251 (OP_A) */\r | |
730 | dtbl = ReadW(op[0].word);\r | |
731 | atbl = (op[0].word+1) & VAMASK;\r | |
732 | reason = cpu_vma_ijmar(in_s,dtbl,atbl,0,intrq,debug); /* calc the virt address to AB */\r | |
733 | break;\r | |
734 | \r | |
735 | case 012: /* .JMAP 105252 (OP_A) */\r | |
736 | dtbl = op[0].word;\r | |
737 | atbl = PC;\r | |
738 | if ((reason = cpu_vma_ijmar(in_d,dtbl,atbl,&ndim,intrq,debug))) /* calc the virtual address to AB */\r | |
739 | return reason;\r | |
740 | t32 = (AR << 16) | (BR & DMASK);\r | |
741 | if ((reason = cpu_vma_lbp(t32,0,PC-2,intrq,debug)))\r | |
742 | return reason;\r | |
743 | if (PC==pcsave)\r | |
744 | PC = (PC + ndim) & VAMASK; /* adjust PC: skip ndim subscript dword ptr */\r | |
745 | break;\r | |
746 | \r | |
747 | case 013: /* .JMAR 105253 (OP_A) */\r | |
748 | dtbl = ReadW(op[0].word);\r | |
749 | atbl = (op[0].word+1) & VAMASK;\r | |
750 | reason = cpu_vma_ijmar(in_d,dtbl,atbl,0,intrq,debug); /* calc the virt address to AB */\r | |
751 | break;\r | |
752 | \r | |
753 | case 014: /* .LPXR 105254 (OP_AA) */\r | |
754 | dop0 = ReadOp(op[0].word,in_d); /* get pointer from arg */\r | |
755 | dop1 = ReadOp(op[1].word,in_d); \r | |
756 | t32 = dop0.dword + dop1.dword; /* add offset to it */ \r | |
757 | reason = cpu_vma_lbp(t32,0,PC-3,intrq,debug);\r | |
758 | break;\r | |
759 | \r | |
760 | case 015: /* .LPX 105255 (OP_A) */\r | |
761 | t32 = (AR << 16) | (BR & DMASK); /* pointer in AB */\r | |
762 | dop0 = ReadOp(op[0].word,in_d);\r | |
763 | reason = cpu_vma_lbp(t32,dop0.dword,PC-2,intrq,debug);\r | |
764 | break;\r | |
765 | \r | |
766 | case 016: /* .LBPR 105256 (OP_A) */\r | |
767 | dop0 = ReadOp(op[0].word,in_d); /* get the pointer */\r | |
768 | reason = cpu_vma_lbp(dop0.dword,0,PC-2,intrq,debug);\r | |
769 | break;\r | |
770 | \r | |
771 | case 017: /* .LBP 105257 (OP_N) */\r | |
772 | t32 = (AR << 16) | (BR & DMASK);\r | |
773 | reason = cpu_vma_lbp(t32,0,PC-1,intrq,debug);\r | |
774 | break;\r | |
775 | }\r | |
776 | \r | |
777 | return reason;\r | |
778 | }\r | |
779 | \r | |
780 | \r | |
781 | /* RTE-IV Extended Memory Area Instructions\r | |
782 | \r | |
783 | The RTE-IV operating system (HP product number 92067A) introduced the\r | |
784 | Extended Memory Area (EMA) instructions. EMA provided a mappable data area\r | |
785 | up to one megaword in size. These three instructions accelerated data\r | |
786 | accesses to variables stored in EMA partitions. Support was limited to\r | |
787 | E/F-Series machines; M-Series machines used software equivalents.\r | |
788 | \r | |
789 | Option implementation by CPU was as follows:\r | |
790 | \r | |
791 | 2114 2115 2116 2100 1000-M 1000-E 1000-F\r | |
792 | ------ ------ ------ ------ ------ ------ ------\r | |
793 | N/A N/A N/A N/A N/A 92067A 92067A\r | |
794 | \r | |
795 | The routines are mapped to instruction codes as follows:\r | |
796 | \r | |
797 | Instr. 1000-E/F Description\r | |
798 | ------ -------- ----------------------------------------------\r | |
799 | .EMIO 105240 EMA I/O\r | |
800 | MMAP 105241 Map physical to logical memory\r | |
801 | [test] 105242 [self test]\r | |
802 | .EMAP 105257 Resolve array element address\r | |
803 | \r | |
804 | Notes:\r | |
805 | \r | |
806 | 1. RTE-IV EMA and RTE-6 VMA instructions share the same address space, so a\r | |
807 | given machine can run one or the other, but not both.\r | |
808 | \r | |
809 | Additional references:\r | |
810 | - RTE-IVB Programmer's Reference Manual (92068-90004, Dec-1983).\r | |
811 | - RTE-IVB Technical Specifications (92068-90013, Jan-1980).\r | |
812 | */\r | |
813 | \r | |
814 | static const OP_PAT op_ema[16] = {\r | |
815 | OP_AKA, OP_AKK, OP_N, OP_N, /* .EMIO MMAP [test] --- */\r | |
816 | OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */\r | |
817 | OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */\r | |
818 | OP_N, OP_N, OP_N, OP_AAA /* --- --- --- .EMAP */\r | |
819 | };\r | |
820 | \r | |
821 | /* calculate the 32 bit EMA subscript for an array */\r | |
822 | static t_bool cpu_ema_resolve(uint32 dtbl,uint32 atbl,uint32* sum)\r | |
823 | {\r | |
824 | int32 sub, act, low, sz;\r | |
825 | uint32 MA, base;\r | |
826 | \r | |
827 | int32 ndim = ReadW(dtbl++); /* # dimensions */\r | |
828 | if (ndim < 0) return FALSE; /* invalid? */\r | |
829 | \r | |
830 | *sum = 0; /* accu for index calc */\r | |
831 | while (ndim > 0) {\r | |
832 | MA = ReadW(atbl++); /* get address of A(N) */\r | |
833 | resolve (MA, &MA, 0);\r | |
834 | act = ReadW(MA); /* A(N) */\r | |
835 | low = ReadW(dtbl++); /* -L(N) */\r | |
836 | sub = SEXT(act) + SEXT(low); /* subscript */\r | |
837 | if (sub & 0xffff8000) return FALSE; /* overflow? */\r | |
838 | *sum += sub; /* accumulate */\r | |
839 | sz = ReadW(dtbl++);\r | |
840 | sz = SEXT(sz);\r | |
841 | if (sz < 0) return FALSE;\r | |
842 | *sum *= sz;\r | |
843 | if (*sum > (512*1024)) return FALSE; /* overflow? */\r | |
844 | ndim--;\r | |
845 | }\r | |
846 | base = (ReadW(dtbl+1)<<16) | (ReadW(dtbl) & 0xffff); /* base of array in EMA */\r | |
847 | if (base & 0x8000000) return FALSE;\r | |
848 | *sum += base; /* calculate address into EMA */\r | |
849 | if (*sum & 0xf8000000) return FALSE; /* overflow? */\r | |
850 | return TRUE;\r | |
851 | }\r | |
852 | \r | |
853 | /* implementation of VIS RTE-IVB EMA support\r | |
854 | * .ERES microcode routine, resolves only EMA addresses\r | |
855 | * Call:\r | |
856 | * .OCT 101474B\r | |
857 | * DEF RTN error return (rtn), good return is rtn+1\r | |
858 | * DEF DUMMY dummy argument for compatibility with .EMAP\r | |
859 | * DEF TABLE[,I] array declaration (dtbl)\r | |
860 | * DEF A(N)[,I] actual subscripts (atbl)\r | |
861 | * DEF A(N-1)[,I]\r | |
862 | * ...\r | |
863 | * DEF A(2)[,I]\r | |
864 | * DEF A(1)[,I]\r | |
865 | * RTN EQU * error return A="20", B="EM"\r | |
866 | * RTN+1 EQU *+1 good return B=logical address\r | |
867 | *\r | |
868 | * TABLE DEC # # dimensions\r | |
869 | * DEC -L(N)\r | |
870 | * DEC D(N-1)\r | |
871 | * DEC -L(N-1) lower bound (n-1)st dim\r | |
872 | * DEC D(N-2) (n-2)st dim \r | |
873 | * ...\r | |
874 | * DEC D(1) 1st dim\r | |
875 | * DEC -L(1) lower bound 1st dim\r | |
876 | * DEC # # words/element\r | |
877 | * OFFSET 1 EMA Low\r | |
878 | * OFFSET 2 EMA High\r | |
879 | */\r | |
880 | t_stat cpu_ema_eres(uint32 *rtn,uint32 dtbl,uint32 atbl,t_bool debug)\r | |
881 | {\r | |
882 | uint32 sum;\r | |
883 | if (cpu_ema_resolve(dtbl,atbl,&sum)) { /* calculate subscript */\r | |
884 | AR = sum & 0xffff;\r | |
885 | BR = sum >> 16;\r | |
886 | if (!(BR & SIGN)) { /* no overflow? */\r | |
887 | (*rtn)++; /* return via good exit */\r | |
888 | return SCPE_OK;\r | |
889 | }\r | |
890 | }\r | |
891 | AR = 0x3230; /* error condition: */\r | |
892 | BR = 0x454d; /* AR = '20', BR = 'EM' */\r | |
893 | return SCPE_OK; /* return via unmodified rtn */\r | |
894 | } \r | |
895 | \r | |
896 | /* implementation of VIS RTE-IVB EMA support\r | |
897 | * .ESEG microcode routine\r | |
898 | * Call:\r | |
899 | * LDA FIRST first map to set\r | |
900 | * LDB N # of maps to set\r | |
901 | * .OCT 101475B/105475B\r | |
902 | * DEF RTN ptr to return\r | |
903 | * DEF TABLE map table\r | |
904 | * RTN EQU * error return A="21", B="EM"\r | |
905 | * RTN+1 EQU *+1 good return B=logical address\r | |
906 | *\r | |
907 | * load maps FIRST to FIRST+N from TABLE, with FIRST = FIRST + LOG_START MSEG\r | |
908 | * update map table in base page. Set LOG_START MSEG=0 if opcode==105475\r | |
909 | */\r | |
910 | t_stat cpu_ema_eseg(uint32* rtn, uint32 IR, uint32 tbl, t_bool debug)\r | |
911 | {\r | |
912 | uint32 xidex,eqt,idext0,idext1;\r | |
913 | uint32 msegsz,phys,msegn,last,emasz,pg0,pg1,pg,i,lp;\r | |
914 | \r | |
915 | if ((BR & SIGN) || BR==0) goto em21; /* #maps not positive? */\r | |
916 | xidex = ReadIO(idx,UMAP); /* read ID extension */\r | |
917 | if (xidex==0) goto em21;\r | |
918 | idext0 = ReadWA(xidex+0); /* get 1st word idext */\r | |
919 | msegsz = idext0 & 037; /* S7 MSEG size */\r | |
920 | WriteIO(xidex+0, idext0 | 0100000, SMAP); /* enforce nonstd MSEG */\r | |
921 | idext1 = ReadWA(xidex+1); /* get 2nd word idext */\r | |
922 | phys = idext1 & 01777; /* S5 phys start of EMA */\r | |
923 | msegn = (idext1 >> 11) & 037; /* S9 get logical start MSEG# */\r | |
924 | if (IR & 04000) { /* opcode == 105475? (.VPRG) */\r | |
925 | msegn = 0; /* log start = 0 */\r | |
926 | msegsz = 32; /* size = full range */\r | |
927 | }\r | |
928 | last = AR-1 + BR; /* last page */\r | |
929 | if (last > msegsz) goto em21; /* too many? error */\r | |
930 | eqt = ReadIO(xeqt,UMAP);\r | |
931 | emasz = (ReadWA(eqt+28) & 01777) - 1; /* S6 EMA size in pages */\r | |
932 | \r | |
933 | /* locations 1740...1777 of user base page contain the map entries we need.\r | |
934 | * They are normally hidden by BP fence, therefore they have to be accessed by\r | |
935 | * another fence-less map register. uCode uses #1 temporarily */\r | |
936 | pg0 = dms_rmap(UMAP+0); /* read map #0 */\r | |
937 | pg1 = dms_rmap(UMAP+1); /* save map #1 */\r | |
938 | dms_wmap(UMAP+1,pg0); /* copy #0 into reg #1 */\r | |
939 | lp = AR + msegn; /* first */\r | |
940 | for (i=0; i<BR; i++) { /* loop over N entries */\r | |
941 | pg = ReadW(tbl++); /* get value from table */\r | |
942 | if ((pg & SIGN) || pg > emasz) pg |= 0140000; /* write protect if outside */\r | |
943 | pg += phys; /* adjust into EMA page range */\r | |
944 | WriteIO(umaps+lp+i, pg, UMAP); /* copy pg to user map */\r | |
945 | //printf("MAP val %oB to reg %d (addr=%oB)\n",pg,lp+i,umaps+lp+i);\r | |
946 | dms_wmap(UMAP+lp+i, pg); /* set DMS reg */\r | |
947 | }\r | |
948 | dms_wmap(UMAP+1,pg1); /* restore map #1 */\r | |
949 | O = 0; /* clear overflow */\r | |
950 | (*rtn)++; /* return via good exit */\r | |
951 | return SCPE_OK;\r | |
952 | \r | |
953 | em21:\r | |
954 | AR = 0x3231; /* error condition: */\r | |
955 | BR = 0x454d; /* AR = '21', BR = 'EM' */\r | |
956 | return SCPE_OK; /* return via unmodified rtn */\r | |
957 | }\r | |
958 | \r | |
959 | /* implementation of VIS RTE-IVB EMA support\r | |
960 | * .VSET microcode routine\r | |
961 | * Call:\r | |
962 | * .OCT 101476B\r | |
963 | * DEF RTN return address\r | |
964 | * DEF VIN input vector\r | |
965 | * DEF VOUT output vector\r | |
966 | * DEF MAPS\r | |
967 | * OCT #SCALARS\r | |
968 | * OCT #VECTORS\r | |
969 | * OCT K 1024/(#words/element)\r | |
970 | * RTN EQU * error return (B,A) = "VI22"\r | |
971 | * RTN+1 EQU *+1 hard return, A = K/IMAX\r | |
972 | * RTN+2 EQU *+2 easy return, A = 0, B = 2* #VCTRS\r | |
973 | */\r | |
974 | t_stat cpu_ema_vset(uint32* rtn, OPS op, t_bool debug)\r | |
975 | {\r | |
976 | uint32 vin = op[0].word; /* S1 */\r | |
977 | uint32 vout = op[1].word; /* S2 */\r | |
978 | uint32 maps = op[2].word; /* S3 */\r | |
979 | uint32 scalars = op[3].word; /* S4 */\r | |
980 | uint32 vectors = op[4].word; /* S5 */\r | |
981 | uint32 k = op[5].word; /* S6 */\r | |
982 | uint32 imax = 0; /* imax S11*/\r | |
983 | uint32 xidex,idext1,mseg,phys, addr, i, MA;\r | |
984 | t_bool negflag = FALSE;\r | |
985 | \r | |
986 | for (i=0; i<scalars; i++) { /* copy scalars */\r | |
987 | XR = ReadW(vin++);\r | |
988 | WriteW(vout++, XR);\r | |
989 | }\r | |
990 | xidex = ReadIO(idx,UMAP); /* get ID extension */\r | |
991 | if (xidex==0) goto vi22; /* NO EMA? error */\r | |
992 | idext1 = ReadWA(xidex+1);\r | |
993 | mseg = (idext1 >> 1) & MSEGMASK; /* S9 get logical start MSEG */\r | |
994 | phys = idext1 & 01777; /* phys start of EMA */\r | |
995 | \r | |
996 | for (i=0; i<vectors; i++) { /* copy vector addresses */\r | |
997 | MA = ReadW(vin++);\r | |
998 | resolve (MA, &MA, 0);\r | |
999 | addr = ReadW(MA) & 0177777; /* LSB */\r | |
1000 | addr |= (ReadW(MA+1)<<16); /* MSB, build address */\r | |
1001 | WriteW(vout++, mseg + (addr & 01777)); /* build and write log addr of vector */\r | |
1002 | addr = (addr >> 10) & 0xffff; /* get page */\r | |
1003 | WriteW(maps++, addr); /* save page# */\r | |
1004 | WriteW(maps++, addr+1); /* save next page# as well */\r | |
1005 | MA = ReadW(vin++); /* get index into Y */\r | |
1006 | resolve(MA, &MA, 0);\r | |
1007 | YR = ReadW(MA); /* get index value */\r | |
1008 | WriteW(vout++, MA); /* copy address of index */\r | |
1009 | if (YR & SIGN) { /* index is negative */\r | |
1010 | negflag = TRUE; /* mark a negative index (HARD) */\r | |
1011 | YR = (~YR + 1) & DMASK; /* make index positive */\r | |
1012 | }\r | |
1013 | if (imax < YR) imax = YR; /* set maximum index */\r | |
1014 | mseg += 04000; /* incr mseg address by 2 more pages */ \r | |
1015 | }\r | |
1016 | MA = ReadW(vin); /* get N index into Y */\r | |
1017 | resolve(MA, &MA, 0);\r | |
1018 | YR = ReadW(MA);\r | |
1019 | WriteW(vout++, MA); vin++; /* copy address of N */\r | |
1020 | \r | |
1021 | if (imax==0) goto easy; /* easy case */\r | |
1022 | AR = k / imax; AR++; /* calculate K/IMAX */\r | |
1023 | if (negflag) goto hard; /* had a negative index? */\r | |
1024 | if (YR > AR) goto hard;\r | |
1025 | \r | |
1026 | easy:\r | |
1027 | (*rtn)++; /* return via exit 2 */\r | |
1028 | AR = 0;\r | |
1029 | \r | |
1030 | hard:\r | |
1031 | (*rtn)++; /* return via exit 1 */\r | |
1032 | BR = 2 * op[4].word; /* B = 2* vectors */\r | |
1033 | return SCPE_OK;\r | |
1034 | \r | |
1035 | vi22: /* error condition */\r | |
1036 | AR=0x3232; /* AR = '22' */ \r | |
1037 | BR=0x5649; /* BR = 'VI' */\r | |
1038 | return SCPE_OK; /* return via unmodified e->rtn */\r | |
1039 | }\r | |
1040 | \r | |
1041 | typedef struct ema4 {\r | |
1042 | uint32 mseg; /* logical start of MSEG */\r | |
1043 | uint32 msegsz; /* size of std mseg in pgs */\r | |
1044 | uint32 pgoff; /* pg # in EMA containing element */\r | |
1045 | uint32 offs; /* offset into page of element */\r | |
1046 | uint32 msoff; /* total offset to element in MSEG */\r | |
1047 | uint32 emasz; /* size of ema in pgs */\r | |
1048 | uint32 msegno; /* # of std mseg */\r | |
1049 | uint32 ipgs; /* # of pgs to start of MSEG */\r | |
1050 | uint32 npgs; /* # of pgs needed */\r | |
1051 | uint32 spmseg; /* first phys pg of MSEG */\r | |
1052 | } EMA4;\r | |
1053 | \r | |
1054 | static t_bool cpu_ema_emas(uint32 dtbl,uint32 atbl,EMA4* e)\r | |
1055 | {\r | |
1056 | uint32 xidex, eqt;\r | |
1057 | uint32 sum, msegsz,pgoff,offs,emasz,msegno,msoff,ipgs;\r | |
1058 | \r | |
1059 | if (!cpu_ema_resolve(dtbl,atbl,&sum)) return FALSE; /* calculate 32 bit index */\r | |
1060 | \r | |
1061 | xidex = ReadIO(idx,UMAP); /* read ID extension */\r | |
1062 | msegsz = ReadWA(xidex+0) & 037; /* S5 # pgs for std MSEG */\r | |
1063 | pgoff = sum >> 10; /* S2 page containing element */\r | |
1064 | offs = sum & 01777; /* S6 offset in page to element */\r | |
1065 | if (pgoff > 1023) return FALSE; /* overflow? */\r | |
1066 | eqt = ReadIO(xeqt,UMAP);\r | |
1067 | emasz = ReadWA(eqt+28) & 01777; /* S EMA size in pages */\r | |
1068 | if (pgoff > emasz) return FALSE; /* outside EMA? */\r | |
1069 | msegno = pgoff / msegsz; /* S4 # of MSEG */\r | |
1070 | msoff = pgoff % msegsz; /* offset within MSEG in pgs */\r | |
1071 | ipgs = pgoff - msoff; /* S7 # pgs to start of MSEG */\r | |
1072 | msoff = msoff << 10; /* offset within MSEG in words */\r | |
1073 | msoff += offs; /* S1 offset to element in words */\r | |
1074 | \r | |
1075 | e->msegsz = msegsz; /* return calculated data */\r | |
1076 | e->pgoff = pgoff;\r | |
1077 | e->offs = offs;\r | |
1078 | e->emasz = emasz;\r | |
1079 | e->msegno = msegno;\r | |
1080 | e->ipgs = ipgs;\r | |
1081 | e->msoff = msoff;\r | |
1082 | return TRUE;\r | |
1083 | }\r | |
1084 | \r | |
1085 | static t_bool cpu_ema_mmap01(EMA4* e)\r | |
1086 | {\r | |
1087 | uint32 xidex,idext0, pg, pg0, pg1, i;\r | |
1088 | \r | |
1089 | uint32 base = e->mseg >> 10; /* get the # of first MSEG DMS reg */\r | |
1090 | xidex = ReadIO(idx,UMAP); /* get ID extension */\r | |
1091 | idext0 = ReadWA(xidex+1);\r | |
1092 | \r | |
1093 | if (e->npgs==0) return FALSE; /* no pages to map? */\r | |
1094 | if ((e->npgs+1+e->ipgs) <= e->emasz) e->npgs++; /* actually map npgs+1 pgs */\r | |
1095 | \r | |
1096 | /* locations 1740...1777 of user base page contain the map entries we need.\r | |
1097 | * They are normally hidden by BP fence, therefore they have to be accessed by\r | |
1098 | * another fence-less map register. uCode uses #1, macro code uses $DVCT (==2)\r | |
1099 | */\r | |
1100 | pg0 = dms_rmap(UMAP+0); /* read base page map# */\r | |
1101 | pg1 = dms_rmap(UMAP+1); /* save map# 1 */\r | |
1102 | dms_wmap(UMAP+1,pg0); /* map #0 into reg #1 */\r | |
1103 | for (i=0; (base+i)<32; i++) {\r | |
1104 | pg = i<e->npgs ? e->spmseg : 0140000; /* write protect if outside */\r | |
1105 | WriteIO(umaps+base+i, pg, UMAP); /* copy pg to user map */\r | |
1106 | //printf("MAP val %d to reg %d (addr=%o)\n",pg,base+i,umaps+base+i);\r | |
1107 | dms_wmap(UMAP+base+i, pg); /* set DMS reg */\r | |
1108 | e->spmseg++;\r | |
1109 | }\r | |
1110 | dms_wmap(UMAP+1,pg1); /* restore map #1 */\r | |
1111 | \r | |
1112 | xidex = ReadIO(idx,UMAP); /* get ID extension */\r | |
1113 | idext0 = ReadWA(xidex+0);\r | |
1114 | if (e->msegno == 0xffff) /* non std mseg */\r | |
1115 | idext0 |= 0x8000; /* set nonstd marker */\r | |
1116 | else\r | |
1117 | idext0 = (idext0 & 037) | (e->msegno<<5); /* set new current mseg# */\r | |
1118 | WriteIO(xidex, idext0, SMAP); /* save back value */\r | |
1119 | AR = 0; /* was successful */\r | |
1120 | return TRUE;\r | |
1121 | }\r | |
1122 | \r | |
1123 | static t_bool cpu_ema_mmap02(EMA4* e)\r | |
1124 | {\r | |
1125 | uint32 xidex, eqt, idext1;\r | |
1126 | uint32 mseg,phys,spmseg,emasz,msegsz,msegno;\r | |
1127 | \r | |
1128 | xidex = ReadIO(idx,UMAP); /* get ID extension */\r | |
1129 | msegsz = ReadWA(xidex+0) & 037; /* P size of std MSEG */\r | |
1130 | idext1 = ReadWA(xidex+1);\r | |
1131 | mseg = (idext1 >> 1) & MSEGMASK; /* S9 get logical start MSEG */\r | |
1132 | phys = idext1 & 01777; /* S phys start of EMA */\r | |
1133 | spmseg = phys + e->ipgs; /* S7 phys pg# of MSEG */\r | |
1134 | msegno = e->ipgs / msegsz;\r | |
1135 | if ((e->ipgs % msegsz) != 0) /* non std MSEG? */\r | |
1136 | msegno = 0xffff; /* S4 yes, set marker */\r | |
1137 | if (e->npgs > msegsz) return FALSE; /* map more pages than MSEG sz? */\r | |
1138 | eqt = ReadIO(xeqt,UMAP);\r | |
1139 | emasz = ReadWA(eqt+28) & 01777; /* B EMA size in pages */\r | |
1140 | if ((e->ipgs+e->npgs) > emasz) return FALSE; /* outside EMA? */ \r | |
1141 | if ((e->ipgs+msegsz) > emasz) /* if MSEG overlaps end of EMA */\r | |
1142 | e->npgs = emasz - e->ipgs; /* only map until end of EMA */\r | |
1143 | \r | |
1144 | e->emasz = emasz; /* copy arguments */\r | |
1145 | e->msegsz = msegsz;\r | |
1146 | e->msegno = msegno;\r | |
1147 | e->spmseg = spmseg;\r | |
1148 | e->mseg = mseg;\r | |
1149 | return cpu_ema_mmap01(e);\r | |
1150 | }\r | |
1151 | \r | |
1152 | static t_stat cpu_ema_mmap(uint32 ipage,uint32 npgs, t_bool debug)\r | |
1153 | {\r | |
1154 | uint32 xidex;\r | |
1155 | EMA4 ema4, *e = &ema4;\r | |
1156 | \r | |
1157 | e->ipgs = ipage; /* S6 set the arguments */\r | |
1158 | e->npgs = npgs; /* S5 */\r | |
1159 | \r | |
1160 | AR = 0;\r | |
1161 | xidex = ReadIO(idx,UMAP); \r | |
1162 | if ((ipage & SIGN) || /* negative page displacement? */\r | |
1163 | (npgs & SIGN) || /* negative # of pages? */\r | |
1164 | xidex == 0 || /* no EMA? */\r | |
1165 | !cpu_ema_mmap02(e)) /* mapping failed? */\r | |
1166 | AR = 0177777; /* return with error */\r | |
1167 | return SCPE_OK; /* leave */\r | |
1168 | }\r | |
1169 | \r | |
1170 | static t_bool cpu_ema_emat(EMA4* e)\r | |
1171 | {\r | |
1172 | uint32 xidex,idext0;\r | |
1173 | uint32 curmseg,phys,msnum,lastpgs;\r | |
1174 | \r | |
1175 | xidex = ReadIO(idx,UMAP); /* read ID extension */\r | |
1176 | idext0 = ReadWA(xidex+0); /* get current segment */\r | |
1177 | curmseg = idext0 >> 5;\r | |
1178 | if ((idext0 & 0100000) || /* was nonstd MSEG? */\r | |
1179 | curmseg != e->msegno) { /* or different MSEG last time? */\r | |
1180 | phys = ReadWA(xidex+1) & 01777; /* physical start pg of EMA */\r | |
1181 | e->spmseg = phys + e->ipgs; /* physical start pg of MSEG */\r | |
1182 | msnum = e->emasz / e->msegsz; /* find last MSEG# */\r | |
1183 | lastpgs = e->emasz % e->msegsz; /* #pgs in last MSEG */\r | |
1184 | if (lastpgs==0) msnum--; /* adjust # of last MSEG */\r | |
1185 | e->npgs = msnum==e->msegno ? lastpgs : e->msegsz; /* for last MSEG, only map available pgs */\r | |
1186 | if (!cpu_ema_mmap01(e)) return FALSE; /* map npgs pages at ipgs */\r | |
1187 | }\r | |
1188 | BR = e->mseg + e->msoff; /* return address of element */\r | |
1189 | return TRUE; /* and everything done */\r | |
1190 | }\r | |
1191 | \r | |
1192 | /* .EMIO microcode routine, resolves element addr for EMA array\r | |
1193 | * and maps the appropriate map segment\r | |
1194 | * \r | |
1195 | * Call:\r | |
1196 | * OCT 105250B\r | |
1197 | * DEF RTN error return (rtn), good return is rtn+1\r | |
1198 | * DEF BUFLEN length of buffer in words (bufl)\r | |
1199 | * DEF TABLE[,I] array declaration (dtbl)\r | |
1200 | * DEF A(N)[,I] actual subscripts (atbl)\r | |
1201 | * DEF A(N-1)[,I]\r | |
1202 | * ...\r | |
1203 | * DEF A(2)[,I]\r | |
1204 | * DEF A(1)[,I]\r | |
1205 | * RTN EQU * error return A="15", B="EM"\r | |
1206 | * RTN+1 EQU *+1 good return B=logical address\r | |
1207 | *\r | |
1208 | * TABLE DEC # # dimensions\r | |
1209 | * DEC -L(N)\r | |
1210 | * DEC D(N-1)\r | |
1211 | * DEC -L(N-1) lower bound (n-1)st dim\r | |
1212 | * DEC D(N-2) (n-2)st dim \r | |
1213 | * ...\r | |
1214 | * DEC D(1) 1st dim\r | |
1215 | * DEC -L(1) lower bound 1st dim\r | |
1216 | * DEC # # words/element\r | |
1217 | * OFFSET 1 EMA Low\r | |
1218 | * OFFSET 2 EMA High\r | |
1219 | */\r | |
1220 | static t_stat cpu_ema_emio(uint32* rtn,uint32 bufl,uint32 dtbl,uint32 atbl,t_bool debug)\r | |
1221 | {\r | |
1222 | uint32 xidex, idext1;\r | |
1223 | uint32 mseg, bufpgs, npgs;\r | |
1224 | EMA4 ema4, *e = &ema4;\r | |
1225 | \r | |
1226 | xidex = ReadIO(idx,UMAP); /* read ID extension */\r | |
1227 | if (bufl & SIGN || /* buffer length negative? */ \r | |
1228 | xidex==0) goto em16; /* no EMA declared? */\r | |
1229 | \r | |
1230 | idext1 = ReadWA(xidex+1); /* |logstrt mseg|d|physstrt ema| */\r | |
1231 | mseg = (idext1 >> 1) & MSEGMASK; /* get logical start MSEG */\r | |
1232 | if (!cpu_ema_emas(dtbl,atbl,e)) goto em16; /* resolve address */\r | |
1233 | bufpgs = (bufl + e->offs) >> 10; /* # of pgs reqd for buffer */\r | |
1234 | if ((bufl + e->offs) & 01777) bufpgs++; /* S11 add 1 if not at pg boundary */\r | |
1235 | if ((bufpgs + e->pgoff) > e->emasz) goto em16; /* exceeds EMA limit? */ \r | |
1236 | npgs = (e->msoff + bufl) >> 10; /* # of pgs reqd for MSEG */\r | |
1237 | if ((e->msoff + bufl) & 01777) npgs++; /* add 1 if not at pg boundary */\r | |
1238 | if (npgs < e->msegsz) {\r | |
1239 | e->mseg = mseg; /* logical stat of MSEG */\r | |
1240 | if (!cpu_ema_emat(e)) goto em16; /* do a std mapping */\r | |
1241 | } else {\r | |
1242 | BR = mseg + e->offs; /* logical start of buffer */\r | |
1243 | e->npgs = bufpgs; /* S5 # pgs required */\r | |
1244 | e->ipgs = e->pgoff; /* S6 page offset to reqd pg */\r | |
1245 | if (!cpu_ema_mmap02(e)) goto em16; /* do nonstd mapping */\r | |
1246 | }\r | |
1247 | (*rtn)++; /* return via good exit */ \r | |
1248 | return SCPE_OK;\r | |
1249 | \r | |
1250 | em16: /* error condition */\r | |
1251 | AR=0x3136; /* AR = '16' */ \r | |
1252 | BR=0x454d; /* BR = 'EM' */\r | |
1253 | return SCPE_OK; /* return via unmodified rtn */\r | |
1254 | }\r | |
1255 | \r | |
1256 | /* .EMAP microcode routine, resolves both EMA/non-EMA calls\r | |
1257 | * Call:\r | |
1258 | * OCT 105257B\r | |
1259 | * DEF RTN error return (rtn), good return is rtn+1\r | |
1260 | * DEF ARRAY[,I] array base (abase)\r | |
1261 | * DEF TABLE[,I] array declaration (dtbl)\r | |
1262 | * DEF A(N)[,I] actual subscripts (atbl)\r | |
1263 | * DEF A(N-1)[,I]\r | |
1264 | * ...\r | |
1265 | * DEF A(2)[,I]\r | |
1266 | * DEF A(1)[,I]\r | |
1267 | * RTN EQU * error return A="15", B="EM"\r | |
1268 | * RTN+1 EQU *+1 good return B=logical address\r | |
1269 | *\r | |
1270 | * TABLE DEC # # dimensions\r | |
1271 | * DEC -L(N)\r | |
1272 | * DEC D(N-1)\r | |
1273 | * DEC -L(N-1) lower bound (n-1)st dim\r | |
1274 | * DEC D(N-2) (n-2)st dim \r | |
1275 | * ...\r | |
1276 | * DEC D(1) 1st dim\r | |
1277 | * DEC -L(1) lower bound 1st dim\r | |
1278 | * DEC # # words/element\r | |
1279 | * OFFSET 1 EMA Low\r | |
1280 | * OFFSET 2 EMA High\r | |
1281 | */\r | |
1282 | static t_stat cpu_ema_emap(uint32* rtn,uint32 abase,uint32 dtbl,uint32 atbl,t_bool debug)\r | |
1283 | {\r | |
1284 | uint32 xidex, eqt, idext0, idext1;\r | |
1285 | int32 sub, act, low, ndim, sz;\r | |
1286 | uint32 offs, pgoff, emasz, phys, msgn, mseg, sum, MA, pg0, pg1;\r | |
1287 | \r | |
1288 | xidex = ReadIO(idx,UMAP); /* read ID Extension */\r | |
1289 | if (xidex) { /* is EMA declared? */\r | |
1290 | idext1 = ReadWA(xidex+1); /* get word 1 of idext */\r | |
1291 | mseg = (idext1 >> 1) & MSEGMASK; /* get logical start MSEG */\r | |
1292 | if (abase >= mseg) { /* EMA reference? */\r | |
1293 | if (!cpu_ema_resolve(dtbl,atbl,&sum)) /* calculate subscript */\r | |
1294 | goto em15;\r | |
1295 | offs = sum & 01777; /* address offset within page */\r | |
1296 | pgoff = sum >> 10; /* ema offset in pages */\r | |
1297 | if (pgoff > 1023) goto em15; /* overflow? */\r | |
1298 | eqt = ReadIO(xeqt,UMAP);\r | |
1299 | emasz = ReadWA(eqt+28) & 01777; /* EMA size in pages */\r | |
1300 | phys = idext1 & 01777; /* physical start pg of EMA */ \r | |
1301 | if (pgoff > emasz) goto em15; /* outside EMA range? */\r | |
1302 | \r | |
1303 | msgn = mseg >> 10; /* get # of 1st MSEG reg */\r | |
1304 | phys += pgoff;\r | |
1305 | \r | |
1306 | pg0 = dms_rmap(UMAP+0); /* read base page map# */\r | |
1307 | pg1 = dms_rmap(UMAP+1); /* save map# 1 */\r | |
1308 | dms_wmap(UMAP+1,pg0); /* map #0 into reg #1 */\r | |
1309 | \r | |
1310 | WriteIO(umaps+msgn, phys, UMAP); /* store 1st mapped pg in user map */\r | |
1311 | dms_wmap(UMAP+msgn, phys); /* and set the map register */\r | |
1312 | phys = (pgoff+1)==emasz ? 0140000 : phys+1; /* protect 2nd map if end of EMA */\r | |
1313 | WriteIO(umaps+msgn+1, phys, UMAP); /* store 2nd mapped pg in user map */\r | |
1314 | dms_wmap(UMAP+msgn+1, phys); /* and set the map register */\r | |
1315 | \r | |
1316 | dms_wmap(UMAP+1,pg1); /* restore map #1 */\r | |
1317 | \r | |
1318 | idext0 = ReadWA(xidex+0) | 0100000; /* set NS flag in id extension */\r | |
1319 | WriteIO(xidex+0, idext0, SMAP); /* save back value */\r | |
1320 | AR = 0; /* was successful */\r | |
1321 | BR = mseg + offs; /* calculate log address */ \r | |
1322 | (*rtn)++; /* return via good exit */\r | |
1323 | return SCPE_OK;\r | |
1324 | }\r | |
1325 | } /* not EMA reference */\r | |
1326 | ndim = ReadW(dtbl++);\r | |
1327 | Content-type: text/html