First Commit of my working state
[simh.git] / HP2100 / hp2100_cpu5.c
Content-type: text/html gitweb.hachti.de Git - simh.git/blame - HP2100/hp2100_cpu5.c


500 - Internal Server Error

Malformed UTF-8 character (fatal) at (eval 5) line 1, <$fd> line 2665.
CommitLineData
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
55t_stat cpu_rte_vma (uint32 IR, uint32 intrq); /* RTE-6 VMA */\r
56t_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
113static 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
121static const uint32 idx = 0001645;\r
122static const uint32 xmata = 0001646;\r
123static const uint32 xi = 0001647;\r
124static const uint32 xeqt = 0001717;\r
125static const uint32 vswp = 0001776;\r
126static const uint32 umaps = 0003740;\r
127static const uint32 page30 = 0074000;\r
128static const uint32 page31 = 0076000;\r
129static 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
139extern int32 sim_step;\r
140extern FILE* sim_log;\r
141\r
142/* MP abort handler */\r
143extern 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
151static t_stat vma_resolve (uint32 MA, uint32 *addr, t_bool debug)\r
152{\r
153uint32 i;\r
154uint32 faultma = MA;\r
155\r
156for (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
160if (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
167return 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
188static t_stat cpu_vma_loc(OPS op,uint32 intrq,t_bool debug)\r
189{\r
190uint32 eqt,mls,pnod,lstpg,fstpg,rotsz,lgpg,relpg,relbp,matloc,ptnpg,physpg,cnt,pgs,umapr;\r
191\r
192eqt = ReadIO(xeqt,UMAP); /* get ID segment */\r
193mls = ReadIO(eqt+33,SMAP); /* get word33 of alternate map */\r
194if ((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
202pnod = mls & 01777; /* get #pages of mem res nodes */\r
203if (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
211lstpg = (ReadIO(eqt+29,SMAP) >> 10) - 1; /* last page# of code */\r
212fstpg = ReadIO(eqt+23,SMAP) >> 10; /* index to 1st addr + mem nodes */\r
213rotsz = fstpg - (ReadIO(eqt+22,SMAP) >> 10); /* #pages in root */\r
214lgpg = op[0].word;\r
215\r
216/* lets do some consistency checks, CPU halt if they fail */\r
217if (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
226relpg = op[1].word;\r
227if (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
236relbp = op[2].word;\r
237if (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
247cnt = lstpg - lgpg + 1; /* #pages to map */\r
248pgs = pnod - relpg + 1; /* #pages from start node to end of code */\r
249if (pgs < cnt) cnt = pgs; /* ensure minimum, so not to map into EMA */\r
250 \r
251matloc = ReadIO(xmata,UMAP); /* get MAT $LOC address */\r
252ptnpg = ReadIO(matloc+3,SMAP) & 01777; /* index to start phys pg */\r
253physpg = ptnpg + relpg; /* phys pg # of node */\r
254umapr = 32 + lgpg; /* map register to start */\r
255\r
256/* do an XMS with AR=umapr,BR=physpg,XR=cnt */\r
257if (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
261while (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
268dms_wmap(32,relbp+ptnpg); /* map base page again */\r
269WriteW(op[3].word,op[4].word); /* path# we are going to */\r
270 \r
271PC = (PC - 8) & DMASK; /* adjust PC to return address */\r
272 /* word before the $LOC microinstr. */\r
273PC = (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
276if (debug)\r
277 fprintf(sim_deb,">>CPU VMA: $LOC done: path#=%06o, P=%06o\n",op[4].word,PC);\r
278return 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
286static t_bool cpu_vma_ptevl(uint32 pagid,uint32* physpg)\r
287{\r
288uint32 suit;\r
289uint32 pteidx = pagid & 0001777; /* build index */\r
290uint32 reqst = pagid & SUITMASK; /* required suit */\r
291uint32 pteval = ReadW(page31 | pteidx); /* get PTE entry */\r
292*physpg = pteval & 0001777; /* store physical page number */\r
293suit = pteval & SUITMASK; /* suit number seen */\r
294if (pteval == NILPAGE) return FALSE; /* NIL value in PTE */\r
295return suit == reqst || !*physpg; /* good page or last+1 */\r
296}\r
297\r
298/* handle page fault */\r
299static 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
302uint32 pre = ReadIO(xi,UMAP); /* get program preamble */\r
303uint32 ema = ReadIO(pre+2,UMAP); /* get address of $EMA$/$VMA$ */\r
304WriteIO(ema,faultpc,UMAP); /* write addr of fault instr */\r
305XR = x; /* X = faulting page */\r
306YR = y; /* Y = faulting address for page */\r
307\r
308if (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
312if (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
319PC = (ema+1) & VAMASK; /* restart $EMA$ user code, */\r
320 /* will return to fault instruction */\r
321\r
322AR = (ptr >> 16) & DMASK; /* restore A, B */\r
323BR = ptr & DMASK;\r
324E = 0; /* enforce E = 0 */\r
325if (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
329return SCPE_OK;\r
330}\r
331\r
332/* map in PTE into last page, return false, if page fault */\r
333static t_bool cpu_vma_mapte(uint32* ptepg)\r
334{\r
335uint32 idext,idext2;\r
336uint32 dispatch = ReadIO(vswp,UMAP) & 01777; /* get fresh dispatch flag */\r
337t_bool swapflag = TRUE;\r
338\r
339if (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
349if (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
354return 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
375static t_stat cpu_vma_lbp(uint32 ptr,uint32 aoffset,uint32 faultpc,uint32 intrq,t_bool debug) \r
376{\r
377uint32 pagid,offset,ptrl,pgidx,ptepg;\r
378uint16 p30,p31,suit;\r
379t_stat reason = SCPE_OK;\r
380uint32 faultab = ptr; /* remember A,B for page fault */\r
381ptr += aoffset; /* add the offset e.g. for .LPX */\r
382\r
383if (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
387O = 0; /* clear overflow */\r
388if (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
399pagid = (ptr >> 10) & DMASK; /* extract page id (16 bit idx, incl suit*/\r
400offset = ptr & 01777; /* and offset */\r
401suit = pagid & SUITMASK; /* suit of page */\r
402pgidx = pagid & PAGEIDX; /* index into PTE */\r
403\r
404if (!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
411p30 = ReadW(page31 | pgidx) ^ suit;\r
412if (!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
417if (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
428p31 = ReadW(page31 | pgidx) ^ suit;\r
429if (!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
439else {\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
448AR = pagid; /* return pagid in A */\r
449BR = page30+offset; /* mapped address in B */\r
450if (debug)\r
451 fprintf(sim_deb,">>CPU VMA: cpu_vma_lbp: map done AR=%06o BR=%o6o\n",AR,BR);\r
452return 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
474static t_stat cpu_vma_pmap(uint32 umapr,uint32 pagid, t_bool debug)\r
475{\r
476uint32 physpg, ptr, pgpte;\r
477uint32 mapnm = umapr & 0x7fff; /* strip off bit 15 */\r
478\r
479if (debug)\r
480 fprintf(sim_deb, ">>CPU VMA: .PMAP AR=%06o(umapr) BR=%06o(pagid)\n",umapr,pagid);\r
481\r
482if (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
489ptr = (umapr << 16) | (pagid & DMASK); /* build the ptr argument for vma_fault */ \r
490if (!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
504if (!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
517E = 1;\r
518if (physpg == 0) /* last+1 page ? */\r
519 physpg = RWPROT; /* yes, use page 1023 RW/Protected */\r
520else E = 0; /* normal page to map */\r
521\r
522dms_wmap(mapnm+UMAP,physpg); /* map page to user page reg */ \r
523if (mapnm != 31) /* unless already unmapped, */\r
524 dms_wmap(31+UMAP,RWPROT); /* unmap PTE */\r
525\r
526AR = (umapr + 1) & DMASK; /* increment mapr for next call */\r
527BR = (pagid + 1) & DMASK; /* increment pagid for next call */\r
528O = 0; /* clear overflow */\r
529PC = (PC + 1) & VAMASK; /* normal PC+2 return */\r
530if (debug)\r
531 fprintf(sim_deb,">>CPU VMA: .PMAP map done: AR=%06o BR=%o6o exit P+2\n",AR,BR);\r
532return 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
558static t_stat cpu_vma_ijmar(OPSIZE ij,uint32 dtbl,uint32 atbl,uint32* dimret,\r
559 uint32 intrq,t_bool debug)\r
560{\r
561t_stat reason = SCPE_OK;\r
562uint32 ndim,MA,i,ws;\r
563int32 accu,ax,dx;\r
564OP din;\r
565int opsz = ij==in_d ? 2 : 1;\r
566\r
567ndim = ReadW(dtbl++); /* get #dimensions itself */\r
568if (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
597if (dimret) *dimret = ndim; /* return dimensions */\r
598if (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
610accu = 0;\r
611while (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
631din = ReadOp(dtbl,in_d); /* add base address */\r
632accu += din.dword;\r
633\r
634AR = (accu >> 16) & DMASK; /* transfer to AB */\r
635BR = accu & DMASK;\r
636if (debug)\r
637 fprintf(sim_deb,">>CPU VMA: resulting virt addr=%o (AR=%06o, BR=%06o)\n",accu,AR,BR);\r
638return reason;\r
639}\r
640\r
641/*\r
642 * This is the main handler for the RTE6/VMA microcodes */\r
643t_stat cpu_rte_vma (uint32 IR, uint32 intrq)\r
644{\r
645t_stat reason = SCPE_OK;\r
646OPS op;\r
647OP_PAT pattern;\r
648uint32 entry,t32,ndim;\r
649uint32 dtbl,atbl; /* descriptor table ptr, actual args ptr */\r
650OP dop0,dop1;\r
651uint32 pcsave = (PC+1) & VAMASK; /* save PC to check for redo in imap/jmap */\r
652t_bool debug = DEBUG_PRI (cpu_dev, DEB_VMA);\r
653\r
654if ((cpu_unit.flags & UNIT_VMAOS) == 0) /* VMA/OS option installed? */\r
655 return cpu_rte_ema (IR, intrq); /* try EMA */\r
656 \r
657entry = IR & 017; /* mask to entry point */\r
658pattern = op_vma[entry]; /* get operand pattern */\r
659\r
660if (pattern != OP_N)\r
661 if (reason = cpu_ops (pattern, op, intrq)) /* get instruction operands */\r
662 return reason;\r
663\r
664if (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
675switch (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
777return 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
814static 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
822static t_bool cpu_ema_resolve(uint32 dtbl,uint32 atbl,uint32* sum)\r
823{\r
824int32 sub, act, low, sz;\r
825uint32 MA, base;\r
826\r
827int32 ndim = ReadW(dtbl++); /* # dimensions */\r
828if (ndim < 0) return FALSE; /* invalid? */\r
829\r
830*sum = 0; /* accu for index calc */\r
831while (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
846base = (ReadW(dtbl+1)<<16) | (ReadW(dtbl) & 0xffff); /* base of array in EMA */\r
847if (base & 0x8000000) return FALSE;\r
848*sum += base; /* calculate address into EMA */\r
849if (*sum & 0xf8000000) return FALSE; /* overflow? */\r
850return 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
880t_stat cpu_ema_eres(uint32 *rtn,uint32 dtbl,uint32 atbl,t_bool debug)\r
881{\r
882uint32 sum;\r
883if (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
891AR = 0x3230; /* error condition: */\r
892BR = 0x454d; /* AR = '20', BR = 'EM' */\r
893return 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
910t_stat cpu_ema_eseg(uint32* rtn, uint32 IR, uint32 tbl, t_bool debug)\r
911{\r
912uint32 xidex,eqt,idext0,idext1;\r
913uint32 msegsz,phys,msegn,last,emasz,pg0,pg1,pg,i,lp;\r
914\r
915if ((BR & SIGN) || BR==0) goto em21; /* #maps not positive? */\r
916xidex = ReadIO(idx,UMAP); /* read ID extension */\r
917if (xidex==0) goto em21;\r
918idext0 = ReadWA(xidex+0); /* get 1st word idext */\r
919msegsz = idext0 & 037; /* S7 MSEG size */\r
920WriteIO(xidex+0, idext0 | 0100000, SMAP); /* enforce nonstd MSEG */\r
921idext1 = ReadWA(xidex+1); /* get 2nd word idext */\r
922phys = idext1 & 01777; /* S5 phys start of EMA */\r
923msegn = (idext1 >> 11) & 037; /* S9 get logical start MSEG# */\r
924if (IR & 04000) { /* opcode == 105475? (.VPRG) */\r
925 msegn = 0; /* log start = 0 */\r
926 msegsz = 32; /* size = full range */\r
927}\r
928last = AR-1 + BR; /* last page */\r
929if (last > msegsz) goto em21; /* too many? error */\r
930eqt = ReadIO(xeqt,UMAP);\r
931emasz = (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
936pg0 = dms_rmap(UMAP+0); /* read map #0 */\r
937pg1 = dms_rmap(UMAP+1); /* save map #1 */\r
938dms_wmap(UMAP+1,pg0); /* copy #0 into reg #1 */\r
939lp = AR + msegn; /* first */\r
940for (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
948dms_wmap(UMAP+1,pg1); /* restore map #1 */\r
949O = 0; /* clear overflow */\r
950(*rtn)++; /* return via good exit */\r
951return SCPE_OK;\r
952\r
953em21:\r
954AR = 0x3231; /* error condition: */\r
955BR = 0x454d; /* AR = '21', BR = 'EM' */\r
956return 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
974t_stat cpu_ema_vset(uint32* rtn, OPS op, t_bool debug)\r
975{\r
976uint32 vin = op[0].word; /* S1 */\r
977uint32 vout = op[1].word; /* S2 */\r
978uint32 maps = op[2].word; /* S3 */\r
979uint32 scalars = op[3].word; /* S4 */\r
980uint32 vectors = op[4].word; /* S5 */\r
981uint32 k = op[5].word; /* S6 */\r
982uint32 imax = 0; /* imax S11*/\r
983uint32 xidex,idext1,mseg,phys, addr, i, MA;\r
984t_bool negflag = FALSE;\r
985\r
986for (i=0; i<scalars; i++) { /* copy scalars */\r
987 XR = ReadW(vin++);\r
988 WriteW(vout++, XR);\r
989}\r
990xidex = ReadIO(idx,UMAP); /* get ID extension */\r
991if (xidex==0) goto vi22; /* NO EMA? error */\r
992idext1 = ReadWA(xidex+1);\r
993mseg = (idext1 >> 1) & MSEGMASK; /* S9 get logical start MSEG */\r
994phys = idext1 & 01777; /* phys start of EMA */\r
995\r
996for (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
1016MA = ReadW(vin); /* get N index into Y */\r
1017resolve(MA, &MA, 0);\r
1018YR = ReadW(MA);\r
1019WriteW(vout++, MA); vin++; /* copy address of N */\r
1020\r
1021if (imax==0) goto easy; /* easy case */\r
1022AR = k / imax; AR++; /* calculate K/IMAX */\r
1023if (negflag) goto hard; /* had a negative index? */\r
1024if (YR > AR) goto hard;\r
1025 \r
1026easy:\r
1027(*rtn)++; /* return via exit 2 */\r
1028AR = 0;\r
1029\r
1030hard:\r
1031(*rtn)++; /* return via exit 1 */\r
1032BR = 2 * op[4].word; /* B = 2* vectors */\r
1033return SCPE_OK;\r
1034\r
1035vi22: /* 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
1041typedef 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
1054static t_bool cpu_ema_emas(uint32 dtbl,uint32 atbl,EMA4* e)\r
1055{\r
1056uint32 xidex, eqt;\r
1057uint32 sum, msegsz,pgoff,offs,emasz,msegno,msoff,ipgs;\r
1058\r
1059if (!cpu_ema_resolve(dtbl,atbl,&sum)) return FALSE; /* calculate 32 bit index */\r
1060\r
1061xidex = ReadIO(idx,UMAP); /* read ID extension */\r
1062msegsz = ReadWA(xidex+0) & 037; /* S5 # pgs for std MSEG */\r
1063pgoff = sum >> 10; /* S2 page containing element */\r
1064offs = sum & 01777; /* S6 offset in page to element */\r
1065if (pgoff > 1023) return FALSE; /* overflow? */\r
1066eqt = ReadIO(xeqt,UMAP);\r
1067emasz = ReadWA(eqt+28) & 01777; /* S EMA size in pages */\r
1068if (pgoff > emasz) return FALSE; /* outside EMA? */\r
1069msegno = pgoff / msegsz; /* S4 # of MSEG */\r
1070msoff = pgoff % msegsz; /* offset within MSEG in pgs */\r
1071ipgs = pgoff - msoff; /* S7 # pgs to start of MSEG */\r
1072msoff = msoff << 10; /* offset within MSEG in words */\r
1073msoff += offs; /* S1 offset to element in words */\r
1074\r
1075e->msegsz = msegsz; /* return calculated data */\r
1076e->pgoff = pgoff;\r
1077e->offs = offs;\r
1078e->emasz = emasz;\r
1079e->msegno = msegno;\r
1080e->ipgs = ipgs;\r
1081e->msoff = msoff;\r
1082return TRUE;\r
1083}\r
1084\r
1085static t_bool cpu_ema_mmap01(EMA4* e)\r
1086{\r
1087uint32 xidex,idext0, pg, pg0, pg1, i;\r
1088\r
1089uint32 base = e->mseg >> 10; /* get the # of first MSEG DMS reg */\r
1090xidex = ReadIO(idx,UMAP); /* get ID extension */\r
1091idext0 = ReadWA(xidex+1);\r
1092\r
1093if (e->npgs==0) return FALSE; /* no pages to map? */\r
1094if ((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
1100pg0 = dms_rmap(UMAP+0); /* read base page map# */\r
1101pg1 = dms_rmap(UMAP+1); /* save map# 1 */\r
1102dms_wmap(UMAP+1,pg0); /* map #0 into reg #1 */\r
1103for (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
1110dms_wmap(UMAP+1,pg1); /* restore map #1 */\r
1111\r
1112xidex = ReadIO(idx,UMAP); /* get ID extension */\r
1113idext0 = ReadWA(xidex+0);\r
1114if (e->msegno == 0xffff) /* non std mseg */\r
1115 idext0 |= 0x8000; /* set nonstd marker */\r
1116else\r
1117 idext0 = (idext0 & 037) | (e->msegno<<5); /* set new current mseg# */\r
1118WriteIO(xidex, idext0, SMAP); /* save back value */\r
1119AR = 0; /* was successful */\r
1120return TRUE;\r
1121}\r
1122\r
1123static t_bool cpu_ema_mmap02(EMA4* e)\r
1124{\r
1125uint32 xidex, eqt, idext1;\r
1126uint32 mseg,phys,spmseg,emasz,msegsz,msegno;\r
1127\r
1128xidex = ReadIO(idx,UMAP); /* get ID extension */\r
1129msegsz = ReadWA(xidex+0) & 037; /* P size of std MSEG */\r
1130idext1 = ReadWA(xidex+1);\r
1131mseg = (idext1 >> 1) & MSEGMASK; /* S9 get logical start MSEG */\r
1132phys = idext1 & 01777; /* S phys start of EMA */\r
1133spmseg = phys + e->ipgs; /* S7 phys pg# of MSEG */\r
1134msegno = e->ipgs / msegsz;\r
1135if ((e->ipgs % msegsz) != 0) /* non std MSEG? */\r
1136 msegno = 0xffff; /* S4 yes, set marker */\r
1137if (e->npgs > msegsz) return FALSE; /* map more pages than MSEG sz? */\r
1138eqt = ReadIO(xeqt,UMAP);\r
1139emasz = ReadWA(eqt+28) & 01777; /* B EMA size in pages */\r
1140if ((e->ipgs+e->npgs) > emasz) return FALSE; /* outside EMA? */ \r
1141if ((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
1144e->emasz = emasz; /* copy arguments */\r
1145e->msegsz = msegsz;\r
1146e->msegno = msegno;\r
1147e->spmseg = spmseg;\r
1148e->mseg = mseg;\r
1149return cpu_ema_mmap01(e);\r
1150}\r
1151\r
1152static t_stat cpu_ema_mmap(uint32 ipage,uint32 npgs, t_bool debug)\r
1153{\r
1154uint32 xidex;\r
1155EMA4 ema4, *e = &ema4;\r
1156\r
1157e->ipgs = ipage; /* S6 set the arguments */\r
1158e->npgs = npgs; /* S5 */\r
1159\r
1160AR = 0;\r
1161xidex = ReadIO(idx,UMAP); \r
1162if ((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
1167return SCPE_OK; /* leave */\r
1168}\r
1169\r
1170static t_bool cpu_ema_emat(EMA4* e)\r
1171{\r
1172uint32 xidex,idext0;\r
1173uint32 curmseg,phys,msnum,lastpgs;\r
1174 \r
1175xidex = ReadIO(idx,UMAP); /* read ID extension */\r
1176idext0 = ReadWA(xidex+0); /* get current segment */\r
1177curmseg = idext0 >> 5;\r
1178if ((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
1188BR = e->mseg + e->msoff; /* return address of element */\r
1189return 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
1220static t_stat cpu_ema_emio(uint32* rtn,uint32 bufl,uint32 dtbl,uint32 atbl,t_bool debug)\r
1221{\r
1222uint32 xidex, idext1;\r
1223uint32 mseg, bufpgs, npgs;\r
1224EMA4 ema4, *e = &ema4;\r
1225\r
1226xidex = ReadIO(idx,UMAP); /* read ID extension */\r
1227if (bufl & SIGN || /* buffer length negative? */ \r
1228 xidex==0) goto em16; /* no EMA declared? */\r
1229\r
1230idext1 = ReadWA(xidex+1); /* |logstrt mseg|d|physstrt ema| */\r
1231mseg = (idext1 >> 1) & MSEGMASK; /* get logical start MSEG */\r
1232if (!cpu_ema_emas(dtbl,atbl,e)) goto em16; /* resolve address */\r
1233bufpgs = (bufl + e->offs) >> 10; /* # of pgs reqd for buffer */\r
1234if ((bufl + e->offs) & 01777) bufpgs++; /* S11 add 1 if not at pg boundary */\r
1235if ((bufpgs + e->pgoff) > e->emasz) goto em16; /* exceeds EMA limit? */ \r
1236npgs = (e->msoff + bufl) >> 10; /* # of pgs reqd for MSEG */\r
1237if ((e->msoff + bufl) & 01777) npgs++; /* add 1 if not at pg boundary */\r
1238if (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
1248return SCPE_OK;\r
1249\r
1250em16: /* error condition */\r
1251AR=0x3136; /* AR = '16' */ \r
1252BR=0x454d; /* BR = 'EM' */\r
1253return 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
1282static t_stat cpu_ema_emap(uint32* rtn,uint32 abase,uint32 dtbl,uint32 atbl,t_bool debug)\r
1283{\r
1284uint32 xidex, eqt, idext0, idext1;\r
1285int32 sub, act, low, ndim, sz;\r
1286uint32 offs, pgoff, emasz, phys, msgn, mseg, sum, MA, pg0, pg1;\r
1287\r
1288xidex = ReadIO(idx,UMAP); /* read ID Extension */\r
1289if (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
1326ndim = ReadW(dtbl++);\r
1327