| 1 | /* pdp10_xtnd.c: PDP-10 extended instruction simulator\r |
| 2 | \r |
| 3 | Copyright (c) 1993-2005, Robert M Supnik\r |
| 4 | \r |
| 5 | Permission is hereby granted, free of charge, to any person obtaining a\r |
| 6 | copy of this software and associated documentation files (the "Software"),\r |
| 7 | to deal in the Software without restriction, including without limitation\r |
| 8 | the rights to use, copy, modify, merge, publish, distribute, sublicense,\r |
| 9 | and/or sell copies of the Software, and to permit persons to whom the\r |
| 10 | Software is furnished to do so, subject to the following conditions:\r |
| 11 | \r |
| 12 | The above copyright notice and this permission notice shall be included in\r |
| 13 | all copies or substantial portions of the Software.\r |
| 14 | \r |
| 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r |
| 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r |
| 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\r |
| 18 | ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r |
| 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r |
| 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r |
| 21 | \r |
| 22 | Except as contained in this notice, the name of Robert M Supnik shall not be\r |
| 23 | used in advertising or otherwise to promote the sale, use or other dealings\r |
| 24 | in this Software without prior written authorization from Robert M Supnik.\r |
| 25 | \r |
| 26 | 12-May-01 RMS Fixed compiler warning in xlate\r |
| 27 | \r |
| 28 | Instructions handled in this module:\r |
| 29 | \r |
| 30 | MOVSLJ move string left justified\r |
| 31 | MOVSO move string offset\r |
| 32 | MOVST move string translated\r |
| 33 | MOVSRJ move string right justified\r |
| 34 | CMPSL compare string, skip on less\r |
| 35 | CMPSE compare string, skip on equal\r |
| 36 | CMPSLE compare string, skip on less or equal\r |
| 37 | CMPSGE compare string, skip on greater or equal\r |
| 38 | CMPSN compare string, skip on unequal\r |
| 39 | CMPSG compare string, skip on greater\r |
| 40 | CVTDBO convert decimal to binary offset\r |
| 41 | CVTDBT convert decimal to binary translated\r |
| 42 | CVTBDO convert binary to decimal offset\r |
| 43 | CVTBDT convert binary to decimal translated\r |
| 44 | EDIT edit\r |
| 45 | \r |
| 46 | The PDP-10 extended instructions deal with non-binary data types,\r |
| 47 | particularly byte strings and decimal strings. (In the KL10, the\r |
| 48 | extended instructions include G floating support as well.) They\r |
| 49 | are very complicated microcoded subroutines that can potentially\r |
| 50 | run for a very long time. Accordingly, the instructions must test\r |
| 51 | for interrupts as well as page faults, and be prepared to restart\r |
| 52 | from either.\r |
| 53 | \r |
| 54 | In general, the simulator attempts to keep the AC block up to date,\r |
| 55 | so that page fails and interrupts can be taken directly at any point.\r |
| 56 | If the AC block is not up to date, memory accessibility must be tested\r |
| 57 | before the actual read or write is done.\r |
| 58 | \r |
| 59 | The extended instruction routine returns a status code as follows:\r |
| 60 | \r |
| 61 | XT_NOSK no skip completion\r |
| 62 | XT_SKIP skip completion\r |
| 63 | XT_MUUO invalid extended instruction\r |
| 64 | */\r |
| 65 | \r |
| 66 | #include "pdp10_defs.h"\r |
| 67 | #include <setjmp.h>\r |
| 68 | \r |
| 69 | #define MM_XSRC (pflgs & XSRC_PXCT)\r |
| 70 | #define MM_XDST (pflgs & XDST_PXCT)\r |
| 71 | #define MM_EA_XSRC ((pflgs & EA_PXCT) && MM_XSRC)\r |
| 72 | #define MM_EA_XDST ((pflgs & EA_PXCT) && MM_XDST)\r |
| 73 | \r |
| 74 | #define XT_CMPSL 001 /* opcodes */\r |
| 75 | #define XT_CMPSE 002\r |
| 76 | #define XT_CMPSLE 003\r |
| 77 | #define XT_EDIT 004\r |
| 78 | #define XT_CMPSGE 005\r |
| 79 | #define XT_CMPSN 006\r |
| 80 | #define XT_CMPSG 007\r |
| 81 | #define XT_CVTDBO 010\r |
| 82 | #define XT_CVTDBT 011\r |
| 83 | #define XT_CVTBDO 012\r |
| 84 | #define XT_CVTBDT 013\r |
| 85 | #define XT_MOVSO 014\r |
| 86 | #define XT_MOVST 015\r |
| 87 | #define XT_MOVSLJ 016\r |
| 88 | #define XT_MOVSRJ 017\r |
| 89 | \r |
| 90 | /* Translation control */\r |
| 91 | \r |
| 92 | #define XT_LFLG 0400000000000 /* L flag */\r |
| 93 | #define XT_SFLG 0400000000000 /* S flag */\r |
| 94 | #define XT_NFLG 0200000000000 /* N flag */\r |
| 95 | #define XT_MFLG 0100000000000 /* M flag */\r |
| 96 | \r |
| 97 | /* Translation table */\r |
| 98 | \r |
| 99 | #define XT_V_CODE 15 /* translation op */\r |
| 100 | #define XT_M_CODE 07\r |
| 101 | #define XT_BYMASK 07777 /* byte mask */\r |
| 102 | #define XT_DGMASK 017 /* digit mask */\r |
| 103 | #define XT_GETCODE(x) ((int32) (((x) >> XT_V_CODE) & XT_M_CODE))\r |
| 104 | \r |
| 105 | /* AC masks */\r |
| 106 | \r |
| 107 | #define XLNTMASK 0000777777777 /* length */\r |
| 108 | #define XFLGMASK 0700000000000 /* flags */\r |
| 109 | #define XT_MBZ 0777000000000 /* must be zero */\r |
| 110 | #define XT_MBZE 0047777000000 /* must be zero, edit */\r |
| 111 | \r |
| 112 | /* Register change log */\r |
| 113 | \r |
| 114 | #define XT_N_RLOG 5 /* entry width */\r |
| 115 | #define XT_M_RLOG ((1 << XT_N_RLOG) - 1) /* entry mask */\r |
| 116 | #define XT_O_RLOG 1 /* entry offset */\r |
| 117 | #define XT_INSRLOG(x,v) v = ((v << XT_N_RLOG) | (((x) + XT_O_RLOG) & XT_M_RLOG))\r |
| 118 | #define XT_REMRLOG(x,v) x = (v & XT_M_RLOG) - XT_O_RLOG; \\r |
| 119 | v = v >> XT_N_RLOG\r |
| 120 | \r |
| 121 | /* Edit */\r |
| 122 | \r |
| 123 | #define ED_V_PBYN 30 /* pattern byte # */\r |
| 124 | #define ED_M_PBYN 03\r |
| 125 | #define ED_PBYNO 0040000000000 /* overflow bit */\r |
| 126 | #define ED_GETPBYN(x) ((int32) (((x) >> ED_V_PBYN) & ED_M_PBYN))\r |
| 127 | #define ED_V_POPC 6 /* pattern byte opcode */\r |
| 128 | #define ED_M_PAT 0777 /* pattern byte mask */\r |
| 129 | #define ED_M_NUM 0077 /* number for msg, etc */\r |
| 130 | #define ED_PBYTE(x,y) ((int32) (((x) >> (27 - (ED_GETPBYN (y) * 9))) & ED_M_PAT))\r |
| 131 | #define ED_STOP 0000 /* stop */\r |
| 132 | #define ED_SELECT 0001 /* select source */\r |
| 133 | #define ED_SIGST 0002 /* start significance */\r |
| 134 | #define ED_FLDSEP 0003 /* field separator */\r |
| 135 | #define ED_EXCHMD 0004 /* exchange mark, dst */\r |
| 136 | #define ED_MESSAG 0100 /* message */\r |
| 137 | #define ED_SKPM 0500 /* skip if M */\r |
| 138 | #define ED_SKPN 0600 /* skip if N */\r |
| 139 | #define ED_SKPA 0700 /* skip always */\r |
| 140 | \r |
| 141 | extern d10 *ac_cur; /* current AC block */\r |
| 142 | extern const d10 bytemask[64];\r |
| 143 | extern int32 flags;\r |
| 144 | extern int32 rlog;\r |
| 145 | extern jmp_buf save_env;\r |
| 146 | \r |
| 147 | extern d10 Read (int32 ea, int32 prv);\r |
| 148 | extern void Write (int32 ea, d10 val, int32 prv);\r |
| 149 | extern a10 calc_ea (d10 inst, int32 prv);\r |
| 150 | extern int32 test_int (void);\r |
| 151 | d10 incbp (d10 bp);\r |
| 152 | d10 incloadbp (int32 ac, int32 pflgs);\r |
| 153 | void incstorebp (d10 val, int32 ac, int32 pflgs);\r |
| 154 | d10 xlate (d10 by, a10 tblad, d10 *xflgs, int32 pflgs);\r |
| 155 | void filldst (d10 fill, int32 ac, d10 cnt, int32 pflgs);\r |
| 156 | \r |
| 157 | static const d10 pwrs10[23][2] = {\r |
| 158 | 0, 0,\r |
| 159 | 0, 1,\r |
| 160 | 0, 10,\r |
| 161 | 0, 100,\r |
| 162 | 0, 1000,\r |
| 163 | 0, 10000,\r |
| 164 | 0, 100000,\r |
| 165 | 0, 1000000,\r |
| 166 | 0, 10000000,\r |
| 167 | 0, 100000000,\r |
| 168 | 0, 1000000000,\r |
| 169 | 0, 10000000000,\r |
| 170 | 2, 31280523264,\r |
| 171 | 29, 3567587328,\r |
| 172 | 291, 1316134912,\r |
| 173 | 2910, 13161349120,\r |
| 174 | 29103, 28534276096,\r |
| 175 | 291038, 10464854016,\r |
| 176 | 2910383, 1569325056,\r |
| 177 | 29103830, 15693250560,\r |
| 178 | 291038304, 19493552128,\r |
| 179 | 2910383045, 23136829440,\r |
| 180 | 29103830456, 25209864192\r |
| 181 | };\r |
| 182 | \r |
| 183 | int xtend (int32 ac, int32 ea, int32 pflgs)\r |
| 184 | {\r |
| 185 | d10 b1, b2, ppi; \r |
| 186 | d10 xinst, xoff, digit, f1, f2, rs[2];\r |
| 187 | d10 xflgs = 0;\r |
| 188 | a10 e1, entad;\r |
| 189 | int32 p1 = ADDAC (ac, 1);\r |
| 190 | int32 p3 = ADDAC (ac, 3);\r |
| 191 | int32 p4 = ADDAC (ac, 4);\r |
| 192 | int32 flg, i, s2, t, pp, pat, xop, xac, ret;\r |
| 193 | \r |
| 194 | xinst = Read (ea, MM_OPND); /* get extended instr */\r |
| 195 | xop = GET_OP (xinst); /* get opcode */\r |
| 196 | xac = GET_AC (xinst); /* get AC */\r |
| 197 | if (xac || (xop == 0) || (xop > XT_MOVSRJ)) return XT_MUUO;\r |
| 198 | rlog = 0; /* clear log */\r |
| 199 | switch (xop) { /* case on opcode */\r |
| 200 | \r |
| 201 | /* String compares - checked against KS10 ucode\r |
| 202 | If both strings are zero length, they are considered equal.\r |
| 203 | Both source and destination lengths are MBZ checked.\r |
| 204 | \r |
| 205 | AC = source1 length\r |
| 206 | AC + 1 = source1 byte pointer\r |
| 207 | AC + 3 = source2 length\r |
| 208 | AC + 4 = source2 byte pointer\r |
| 209 | */\r |
| 210 | \r |
| 211 | case XT_CMPSL: /* CMPSL */\r |
| 212 | case XT_CMPSE: /* CMPSE */\r |
| 213 | case XT_CMPSLE: /* CMPSLE */\r |
| 214 | case XT_CMPSGE: /* CMPSGE */\r |
| 215 | case XT_CMPSN: /* CMPSN */\r |
| 216 | case XT_CMPSG: /* CMPSG */\r |
| 217 | if ((AC(ac) | AC(p3)) & XT_MBZ) return XT_MUUO; /* check length MBZ */\r |
| 218 | f1 = Read (ADDA (ea, 1), MM_OPND) & bytemask[GET_S (AC(p1))];\r |
| 219 | f2 = Read (ADDA (ea, 2), MM_OPND) & bytemask[GET_S (AC(p4))];\r |
| 220 | b1 = b2 = 0;\r |
| 221 | for (flg = 0; (AC(ac) | AC(p3)) && (b1 == b2); flg++) {\r |
| 222 | if (flg && (t = test_int ())) ABORT (t);\r |
| 223 | rlog = 0; /* clear log */\r |
| 224 | if (AC(ac)) b1 = incloadbp (p1, pflgs); /* src1 */\r |
| 225 | else b1 = f1;\r |
| 226 | if (AC(p3)) b2 = incloadbp (p4, pflgs); /* src2 */\r |
| 227 | else b2 = f2;\r |
| 228 | if (AC(ac)) AC(ac) = (AC(ac) - 1) & XLNTMASK;\r |
| 229 | if (AC(p3)) AC(p3) = (AC(p3) - 1) & XLNTMASK;\r |
| 230 | }\r |
| 231 | switch (xop) {\r |
| 232 | case XT_CMPSL:\r |
| 233 | return (b1 < b2)? XT_SKIP: XT_NOSK;\r |
| 234 | case XT_CMPSE:\r |
| 235 | return (b1 == b2)? XT_SKIP: XT_NOSK;\r |
| 236 | case XT_CMPSLE:\r |
| 237 | return (b1 <= b2)? XT_SKIP: XT_NOSK;\r |
| 238 | case XT_CMPSGE:\r |
| 239 | return (b1 >= b2)? XT_SKIP: XT_NOSK;\r |
| 240 | case XT_CMPSN:\r |
| 241 | return (b1 != b2)? XT_SKIP: XT_NOSK;\r |
| 242 | case XT_CMPSG:\r |
| 243 | return (b1 > b2)? XT_SKIP: XT_NOSK;\r |
| 244 | }\r |
| 245 | \r |
| 246 | return XT_MUUO;\r |
| 247 | \r |
| 248 | /* Convert binary to decimal instructions - checked against KS10 ucode\r |
| 249 | There are no MBZ tests.\r |
| 250 | \r |
| 251 | AC'AC + 1 = double precision integer source\r |
| 252 | AC + 3 = flags and destination length\r |
| 253 | AC + 4 = destination byte pointer\r |
| 254 | */\r |
| 255 | \r |
| 256 | case XT_CVTBDO: /* CVTBDO */\r |
| 257 | case XT_CVTBDT: /* CVTBDT */\r |
| 258 | e1 = calc_ea (xinst, MM_EA); /* get ext inst addr */\r |
| 259 | if (xop == XT_CVTBDO) /* offset? */\r |
| 260 | xoff = (e1 & RSIGN)? (e1 | LMASK): e1; /* get offset */\r |
| 261 | rs[0] = AC(ac); /* get src opnd */\r |
| 262 | rs[1] = CLRS (AC(p1));\r |
| 263 | if (!TSTF (F_FPD)) { /* set up done yet? */\r |
| 264 | if (TSTS (AC(ac))) { DMOVN (rs); } /* get abs value */\r |
| 265 | for (i = 22; i > 1; i--) { /* find field width */\r |
| 266 | if (DCMPGE (rs, pwrs10[i])) break;\r |
| 267 | }\r |
| 268 | if (i > (AC(p3) & XLNTMASK)) return XT_NOSK;\r |
| 269 | if ((i < (AC(p3) & XLNTMASK)) && (AC(p3) & XT_LFLG)) {\r |
| 270 | f1 = Read (ADDA (ea, 1), MM_OPND);\r |
| 271 | filldst (f1, p3, (AC(p3) & XLNTMASK) - i, pflgs);\r |
| 272 | }\r |
| 273 | else AC(p3) = (AC(p3) & XFLGMASK) | i;\r |
| 274 | if (TSTS (AC(ac))) AC(p3) = AC(p3) | XT_MFLG;\r |
| 275 | if (AC(ac) | AC(p1)) AC(p3) = AC(p3) | XT_NFLG;\r |
| 276 | AC(ac) = rs[0]; /* update state */\r |
| 277 | AC(p1) = rs[1];\r |
| 278 | SETF (F_FPD); /* mark set up done */\r |
| 279 | }\r |
| 280 | \r |
| 281 | /* Now do actual binary to decimal conversion */\r |
| 282 | \r |
| 283 | for (flg = 0; AC(p3) & XLNTMASK; flg++) {\r |
| 284 | if (flg && (t = test_int ())) ABORT (t);\r |
| 285 | rlog = 0; /* clear log */\r |
| 286 | i = (int32) AC(p3) & XLNTMASK; /* get length */\r |
| 287 | if (i > 22) i = 22; /* put in range */\r |
| 288 | for (digit = 0; (digit < 10) && DCMPGE (rs, pwrs10[i]); digit++) {\r |
| 289 | rs[0] = rs[0] - pwrs10[i][0] - (rs[1] < pwrs10[i][1]);\r |
| 290 | rs[1] = (rs[1] - pwrs10[i][1]) & MMASK;\r |
| 291 | }\r |
| 292 | if (xop == XT_CVTBDO) digit = (digit + xoff) & DMASK;\r |
| 293 | else {\r |
| 294 | f1 = Read (e1 + (int32) digit, MM_OPND);\r |
| 295 | if ((i == 1) && (AC(p3) & XT_LFLG)) f1 = f1 >> 18;\r |
| 296 | digit = f1 & RMASK;\r |
| 297 | }\r |
| 298 | incstorebp (digit, p4, pflgs); /* store digit */\r |
| 299 | AC(ac) = rs[0]; /* mem access ok */\r |
| 300 | AC(p1) = rs[1]; /* update state */\r |
| 301 | AC(p3) = (AC(p3) & XFLGMASK) | ((AC(p3) - 1) & XLNTMASK);\r |
| 302 | }\r |
| 303 | CLRF (F_FPD); /* clear FPD */\r |
| 304 | return XT_SKIP;\r |
| 305 | \r |
| 306 | /* Convert decimal to binary instructions - checked against KS10 ucode\r |
| 307 | There are no MBZ tests.\r |
| 308 | \r |
| 309 | AC = flags and source length\r |
| 310 | AC + 1 = source byte pointer\r |
| 311 | AC + 3'AC + 4 = double precision integer result\r |
| 312 | */\r |
| 313 | \r |
| 314 | case XT_CVTDBT: /* CVTDBT */\r |
| 315 | case XT_CVTDBO: /* CVTDBO */\r |
| 316 | e1 = calc_ea (xinst, MM_EA); /* get ext inst addr */\r |
| 317 | if ((AC(ac) & XT_SFLG) == 0) AC(p3) = AC(p4) = 0; /* !S? clr res */\r |
| 318 | else AC(p4) = CLRS (AC(p4)); /* clear low sign */\r |
| 319 | if (xop == XT_CVTDBO) { /* offset? */\r |
| 320 | xoff = (e1 & RSIGN)? (e1 | LMASK): e1; /* get offset */\r |
| 321 | AC(ac) = AC(ac) | XT_SFLG; /* set S flag */\r |
| 322 | }\r |
| 323 | xflgs = AC(ac) & XFLGMASK; /* get xlation flags */\r |
| 324 | for (flg = 0; AC(ac) & XLNTMASK; flg++) {\r |
| 325 | if (flg && (t = test_int ())) ABORT (t);\r |
| 326 | rlog = 0; /* clear log */\r |
| 327 | b1 = incloadbp (p1, pflgs); /* get byte */\r |
| 328 | if (xop == XT_CVTDBO) b1 = (b1 + xoff) & DMASK;\r |
| 329 | else {\r |
| 330 | b1 = xlate (b1, e1, &xflgs, MM_OPND);\r |
| 331 | if (b1 < 0) { /* terminated? */\r |
| 332 | AC(ac) = xflgs | ((AC(ac) - 1) & XLNTMASK);\r |
| 333 | if (TSTS (AC(p3))) AC(p4) = SETS (AC(p4)); \r |
| 334 | return XT_NOSK;\r |
| 335 | }\r |
| 336 | if (xflgs & XT_SFLG) b1 = b1 & XT_DGMASK;\r |
| 337 | else b1 = 0;\r |
| 338 | }\r |
| 339 | AC(ac) = xflgs | ((AC(ac) - 1) & XLNTMASK);\r |
| 340 | if ((b1 < 0) || (b1 > 9)) { /* bad digit? done */\r |
| 341 | if (TSTS (AC(p3))) AC(p4) = SETS (AC(p4)); \r |
| 342 | return XT_NOSK;\r |
| 343 | }\r |
| 344 | AC(p4) = (AC(p4) * 10) + b1; /* base * 10 + digit */\r |
| 345 | AC(p3) = ((AC(p3) * 10) + (AC(p4) >> 35)) & DMASK;\r |
| 346 | AC(p4) = AC(p4) & MMASK;\r |
| 347 | }\r |
| 348 | if (AC(ac) & XT_MFLG) {\r |
| 349 | AC(p4) = -AC(p4) & MMASK;\r |
| 350 | AC(p3) = (~AC(p3) + (AC(p4) == 0)) & DMASK;\r |
| 351 | }\r |
| 352 | if (TSTS (AC(p3))) AC(p4) = SETS (AC(p4)); \r |
| 353 | return XT_SKIP;\r |
| 354 | \r |
| 355 | /* String move instructions - checked against KS10 ucode\r |
| 356 | Only the destination length is MBZ checked.\r |
| 357 | \r |
| 358 | AC = flags (MOVST only) and source length\r |
| 359 | AC + 1 = source byte pointer\r |
| 360 | AC + 3 = destination length\r |
| 361 | AC + 4 = destination byte pointer\r |
| 362 | */\r |
| 363 | \r |
| 364 | case XT_MOVSO: /* MOVSO */\r |
| 365 | case XT_MOVST: /* MOVST */\r |
| 366 | case XT_MOVSRJ: /* MOVSRJ */\r |
| 367 | case XT_MOVSLJ: /* MOVSLJ */\r |
| 368 | if (AC(p3) & XT_MBZ) return XT_MUUO; /* test dst lnt MBZ */\r |
| 369 | f1 = Read (ADDA (ea, 1), MM_OPND); /* get fill */\r |
| 370 | switch (xop) { /* case on instr */\r |
| 371 | \r |
| 372 | case XT_MOVSO: /* MOVSO */\r |
| 373 | AC(ac) = AC(ac) & XLNTMASK; /* trim src length */\r |
| 374 | xoff = calc_ea (xinst, MM_EA); /* get offset */\r |
| 375 | if (xoff & RSIGN) xoff = xoff | LMASK; /* sign extend 18b */\r |
| 376 | s2 = GET_S (AC(p4)); /* get dst byte size */\r |
| 377 | break;\r |
| 378 | \r |
| 379 | case XT_MOVST: /* MOVST */\r |
| 380 | e1 = calc_ea (xinst, MM_EA); /* get xlate tbl addr */\r |
| 381 | break;\r |
| 382 | \r |
| 383 | case XT_MOVSRJ: /* MOVSRJ */\r |
| 384 | AC(ac) = AC(ac) & XLNTMASK; /* trim src length */\r |
| 385 | if (AC(p3) == 0) return (AC(ac)? XT_NOSK: XT_SKIP);\r |
| 386 | if (AC(ac) > AC(p3)) { /* adv src ptr */\r |
| 387 | for (flg = 0; AC(ac) > AC(p3); flg++) {\r |
| 388 | if (flg && (t = test_int ())) ABORT (t);\r |
| 389 | AC(p1) = incbp (AC(p1));\r |
| 390 | AC(ac) = (AC(ac) - 1) & XLNTMASK;\r |
| 391 | }\r |
| 392 | }\r |
| 393 | else if (AC(ac) < AC(p3))\r |
| 394 | filldst (f1, p3, AC(p3) - AC(ac), pflgs);\r |
| 395 | break;\r |
| 396 | \r |
| 397 | case XT_MOVSLJ: /* MOVSLJ */\r |
| 398 | AC(ac) = AC(ac) & XLNTMASK; /* trim src length */\r |
| 399 | break;\r |
| 400 | } /* end case xop */\r |
| 401 | \r |
| 402 | xflgs = AC(ac) & XFLGMASK; /* get xlation flags */\r |
| 403 | if (AC(p3) == 0) return (AC(ac)? XT_NOSK: XT_SKIP);\r |
| 404 | for (flg = 0; AC(p3) & XLNTMASK; flg++) {\r |
| 405 | if (flg && (t = test_int ())) ABORT (t);\r |
| 406 | rlog = 0; /* clear log */\r |
| 407 | if (AC(ac) & XLNTMASK) { /* any source? */\r |
| 408 | b1 = incloadbp (p1, pflgs); /* src byte */\r |
| 409 | if (xop == XT_MOVSO) { /* offset? */\r |
| 410 | b1 = (b1 + xoff) & DMASK; /* test fit */\r |
| 411 | if (b1 & ~bytemask[s2]) {\r |
| 412 | AC(ac) = xflgs | ((AC(ac) - 1) & XLNTMASK);\r |
| 413 | return XT_NOSK;\r |
| 414 | }\r |
| 415 | }\r |
| 416 | else if (xop == XT_MOVST) { /* translate? */\r |
| 417 | b1 = xlate (b1, e1, &xflgs, MM_OPND);\r |
| 418 | if (b1 < 0) { /* upd flags in AC */\r |
| 419 | AC(ac) = xflgs | ((AC(ac) - 1) & XLNTMASK);\r |
| 420 | return XT_NOSK;\r |
| 421 | }\r |
| 422 | if (xflgs & XT_SFLG) b1 = b1 & XT_BYMASK;\r |
| 423 | else b1 = -1;\r |
| 424 | } \r |
| 425 | }\r |
| 426 | else b1 = f1;\r |
| 427 | if (b1 >= 0) { /* valid byte? */\r |
| 428 | incstorebp (b1, p4, pflgs); /* store byte */\r |
| 429 | AC(p3) = (AC(p3) - 1) & XLNTMASK; /* update state */\r |
| 430 | }\r |
| 431 | if (AC(ac) & XLNTMASK) AC(ac) = xflgs | ((AC(ac) - 1) & XLNTMASK);\r |
| 432 | }\r |
| 433 | return (AC(ac) & XLNTMASK)? XT_NOSK: XT_SKIP;\r |
| 434 | \r |
| 435 | /* Edit - checked against KS10 ucode\r |
| 436 | Only the flags/pattern pointer word is MBZ checked.\r |
| 437 | \r |
| 438 | AC = flags, pattern pointer\r |
| 439 | AC + 1 = source byte pointer\r |
| 440 | AC + 3 = mark address\r |
| 441 | AC + 4 = destination byte pointer\r |
| 442 | */\r |
| 443 | \r |
| 444 | case XT_EDIT: /* EDIT */\r |
| 445 | if (AC(ac) & XT_MBZE) return XT_MUUO; /* check pattern MBZ */\r |
| 446 | xflgs = AC(ac) & XFLGMASK; /* get xlation flags */\r |
| 447 | e1 = calc_ea (xinst, MM_EA); /* get xlate tbl addr */\r |
| 448 | for (ppi = 1, ret = -1, flg = 0; ret < 0; flg++, ppi = 1) {\r |
| 449 | if (flg && (t = test_int ())) ABORT (t);\r |
| 450 | rlog = 0; /* clear log */\r |
| 451 | pp = (int32) AC(ac) & AMASK; /* get pattern ptr */\r |
| 452 | b1 = Read (pp, MM_OPND); /* get pattern word */\r |
| 453 | pat = ED_PBYTE (b1, AC(ac)); /* get pattern byte */\r |
| 454 | switch ((pat < 0100)? pat: ((pat >> ED_V_POPC) + 0100)) {\r |
| 455 | \r |
| 456 | case ED_STOP: /* stop */\r |
| 457 | ret = XT_SKIP; /* exit loop */\r |
| 458 | break;\r |
| 459 | \r |
| 460 | case ED_SELECT: /* select source */\r |
| 461 | b1 = incloadbp (p1, pflgs); /* get src */\r |
| 462 | entad = (e1 + ((int32) b1 >> 1)) & AMASK;\r |
| 463 | f1 = ((Read (entad, MM_OPND) >> ((b1 & 1)? 0: 18)) & RMASK);\r |
| 464 | i = XT_GETCODE (f1);\r |
| 465 | if (i & 2) xflgs = \r |
| 466 | (i & 1)? xflgs | XT_MFLG: xflgs & ~XT_MFLG;\r |
| 467 | switch (i) {\r |
| 468 | \r |
| 469 | case 00: case 02: case 03:\r |
| 470 | if (xflgs & XT_SFLG) f1 = f1 & XT_BYMASK;\r |
| 471 | else {\r |
| 472 | f1 = Read (INCA (ea), MM_OPND);\r |
| 473 | if (f1 == 0) break;\r |
| 474 | }\r |
| 475 | incstorebp (f1, p4, pflgs);\r |
| 476 | break;\r |
| 477 | \r |
| 478 | case 01:\r |
| 479 | ret = XT_NOSK; /* exit loop */\r |
| 480 | break;\r |
| 481 | \r |
| 482 | case 04: case 06: case 07:\r |
| 483 | xflgs = xflgs | XT_NFLG;\r |
| 484 | f1 = f1 & XT_BYMASK;\r |
| 485 | if ((xflgs & XT_SFLG) == 0) {\r |
| 486 | f2 = Read (ADDA (ea, 2), MM_OPND);\r |
| 487 | Write ((a10) AC(p3), AC(p4), MM_OPND);\r |
| 488 | if (f2) incstorebp (f2, p4, pflgs);\r |
| 489 | xflgs = xflgs | XT_SFLG;\r |
| 490 | }\r |
| 491 | incstorebp (f1, p4, pflgs);\r |
| 492 | break;\r |
| 493 | \r |
| 494 | case 05:\r |
| 495 | xflgs = xflgs | XT_NFLG;\r |
| 496 | ret = XT_NOSK; /* exit loop */\r |
| 497 | break;\r |
| 498 | } /* end case xlate op */\r |
| 499 | break;\r |
| 500 | \r |
| 501 | case ED_SIGST: /* start significance */\r |
| 502 | if ((xflgs & XT_SFLG) == 0) {\r |
| 503 | f2 = Read (ADDA (ea, 2), MM_OPND);\r |
| 504 | Write ((a10) AC(p3), AC(p4), MM_OPND);\r |
| 505 | if (f2) incstorebp (f2, p4, pflgs);\r |
| 506 | xflgs = xflgs | XT_SFLG;\r |
| 507 | }\r |
| 508 | break;\r |
| 509 | \r |
| 510 | case ED_FLDSEP: /* separate fields */\r |
| 511 | xflgs = 0;\r |
| 512 | break;\r |
| 513 | \r |
| 514 | case ED_EXCHMD: /* exchange */\r |
| 515 | f2 = Read ((int32) (AC(p3) & AMASK), MM_OPND);\r |
| 516 | Write ((int32) (AC(p3) & AMASK), AC(p4), MM_OPND);\r |
| 517 | AC(p4) = f2;\r |
| 518 | break;\r |
| 519 | \r |
| 520 | case (0100 + (ED_MESSAG >> ED_V_POPC)): /* message */\r |
| 521 | if (xflgs & XT_SFLG)\r |
| 522 | f1 = Read (ea + (pat & ED_M_NUM) + 1, MM_OPND);\r |
| 523 | else {\r |
| 524 | f1 = Read (ea + 1, MM_OPND);\r |
| 525 | if (f1 == 0) break;\r |
| 526 | }\r |
| 527 | incstorebp (f1, p4, pflgs);\r |
| 528 | break;\r |
| 529 | \r |
| 530 | case (0100 + (ED_SKPM >> ED_V_POPC)): /* skip on M */\r |
| 531 | if (xflgs & XT_MFLG) ppi = (pat & ED_M_NUM) + 2;\r |
| 532 | break;\r |
| 533 | \r |
| 534 | case (0100 + (ED_SKPN >> ED_V_POPC)): /* skip on N */\r |
| 535 | if (xflgs & XT_NFLG) ppi = (pat & ED_M_NUM) + 2;\r |
| 536 | break;\r |
| 537 | \r |
| 538 | case (0100 + (ED_SKPA >> ED_V_POPC)): /* skip always */\r |
| 539 | ppi = (pat & ED_M_NUM) + 2;\r |
| 540 | break;\r |
| 541 | \r |
| 542 | default: /* NOP or undefined */\r |
| 543 | break;\r |
| 544 | } /* end case pttrn op */\r |
| 545 | AC(ac) = AC(ac) + ((ppi & ED_M_PBYN) << ED_V_PBYN);\r |
| 546 | AC(ac) = AC(ac) + (ppi >> 2) + ((AC(ac) & ED_PBYNO)? 1: 0);\r |
| 547 | AC(ac) = xflgs | (AC(ac) & ~(XT_MBZE | XFLGMASK));\r |
| 548 | }\r |
| 549 | return ret;\r |
| 550 | } /* end case xop */\r |
| 551 | return XT_MUUO;\r |
| 552 | }\r |
| 553 | \r |
| 554 | /* Supporting subroutines */\r |
| 555 | \r |
| 556 | /* Increment byte pointer, register version */\r |
| 557 | \r |
| 558 | d10 incbp (d10 bp)\r |
| 559 | {\r |
| 560 | int32 p, s;\r |
| 561 | \r |
| 562 | p = GET_P (bp); /* get P and S */\r |
| 563 | s = GET_S (bp);\r |
| 564 | p = p - s; /* adv P */\r |
| 565 | if (p < 0) { /* end of word? */\r |
| 566 | bp = (bp & LMASK) | (INCR (bp)); /* increment addr */\r |
| 567 | p = (36 - s) & 077; /* reset P */\r |
| 568 | }\r |
| 569 | bp = PUT_P (bp, p); /* store new P */\r |
| 570 | return bp;\r |
| 571 | }\r |
| 572 | \r |
| 573 | /* Increment and load byte, extended version - uses register log */\r |
| 574 | \r |
| 575 | d10 incloadbp (int32 ac, int32 pflgs)\r |
| 576 | {\r |
| 577 | a10 ba;\r |
| 578 | d10 bp, wd;\r |
| 579 | int32 p, s;\r |
| 580 | \r |
| 581 | bp = AC(ac) = incbp (AC(ac)); /* increment bp */\r |
| 582 | XT_INSRLOG (ac, rlog); /* log change */\r |
| 583 | p = GET_P (bp); /* get P and S */\r |
| 584 | s = GET_S (bp);\r |
| 585 | ba = calc_ea (bp, MM_EA_XSRC); /* calc bp eff addr */\r |
| 586 | wd = Read (ba, MM_XSRC); /* read word */\r |
| 587 | wd = (wd >> p) & bytemask[s]; /* get byte */\r |
| 588 | return wd;\r |
| 589 | }\r |
| 590 | \r |
| 591 | /* Increment and deposit byte, extended version - uses register log */\r |
| 592 | \r |
| 593 | void incstorebp (d10 val, int32 ac, int32 pflgs)\r |
| 594 | {\r |
| 595 | a10 ba;\r |
| 596 | d10 bp, wd, mask;\r |
| 597 | int32 p, s;\r |
| 598 | \r |
| 599 | bp = AC(ac) = incbp (AC(ac)); /* increment bp */\r |
| 600 | XT_INSRLOG (ac, rlog); /* log change */\r |
| 601 | p = GET_P (bp); /* get P and S */\r |
| 602 | s = GET_S (bp);\r |
| 603 | ba = calc_ea (bp, MM_EA_XDST); /* calc bp eff addr */\r |
| 604 | wd = Read (ba, MM_XDST); /* read, write test */\r |
| 605 | mask = bytemask[s] << p; /* shift mask, val */\r |
| 606 | val = val << p;\r |
| 607 | wd = (wd & ~mask) | (val & mask); /* insert byte */\r |
| 608 | Write (ba, wd & DMASK, MM_XDST);\r |
| 609 | return;\r |
| 610 | }\r |
| 611 | \r |
| 612 | /* Translate byte\r |
| 613 | \r |
| 614 | Arguments\r |
| 615 | by = byte to translate\r |
| 616 | tblad = virtual address of translation table\r |
| 617 | *xflgs = pointer to word containing translation flags\r |
| 618 | prv = previous mode flag for table lookup\r |
| 619 | Returns\r |
| 620 | xby = >= 0, translated byte\r |
| 621 | < 0, terminate translation\r |
| 622 | */\r |
| 623 | \r |
| 624 | d10 xlate (d10 by, a10 tblad, d10 *xflgs, int32 prv)\r |
| 625 | {\r |
| 626 | a10 ea;\r |
| 627 | int32 tcode;\r |
| 628 | d10 tblent;\r |
| 629 | \r |
| 630 | ea = (tblad + ((int32) by >> 1)) & AMASK;\r |
| 631 | tblent = ((Read (ea, prv) >> ((by & 1)? 0: 18)) & RMASK);\r |
| 632 | tcode = XT_GETCODE (tblent); /* get xlate code */\r |
| 633 | switch (tcode) {\r |
| 634 | \r |
| 635 | case 00:\r |
| 636 | return (*xflgs & XT_SFLG)? tblent: by;\r |
| 637 | \r |
| 638 | case 01:\r |
| 639 | break;\r |
| 640 | \r |
| 641 | case 02:\r |
| 642 | *xflgs = *xflgs & ~XT_MFLG;\r |
| 643 | return (*xflgs & XT_SFLG)? tblent: by;\r |
| 644 | \r |
| 645 | case 03:\r |
| 646 | *xflgs = *xflgs | XT_MFLG;\r |
| 647 | return (*xflgs & XT_SFLG)? tblent: by;\r |
| 648 | \r |
| 649 | case 04:\r |
| 650 | *xflgs = *xflgs | XT_SFLG | XT_NFLG;\r |
| 651 | return tblent;\r |
| 652 | \r |
| 653 | case 05:\r |
| 654 | *xflgs = *xflgs | XT_NFLG;\r |
| 655 | break;\r |
| 656 | \r |
| 657 | case 06:\r |
| 658 | *xflgs = (*xflgs | XT_SFLG | XT_NFLG) & ~XT_MFLG;\r |
| 659 | return tblent;\r |
| 660 | \r |
| 661 | case 07:\r |
| 662 | *xflgs = *xflgs | XT_SFLG | XT_NFLG | XT_MFLG;\r |
| 663 | return tblent;\r |
| 664 | } /* end case */\r |
| 665 | \r |
| 666 | return -1;\r |
| 667 | }\r |
| 668 | \r |
| 669 | /* Fill out the destination string\r |
| 670 | \r |
| 671 | Arguments:\r |
| 672 | fill = fill\r |
| 673 | ac = 2 word AC block (length, byte pointer)\r |
| 674 | cnt = fill count\r |
| 675 | pflgs = PXCT flags\r |
| 676 | */\r |
| 677 | \r |
| 678 | void filldst (d10 fill, int32 ac, d10 cnt, int32 pflgs)\r |
| 679 | {\r |
| 680 | int32 i, t;\r |
| 681 | int32 p1 = ADDA (ac, 1);\r |
| 682 | \r |
| 683 | for (i = 0; i < cnt; i++) {\r |
| 684 | if (i && (t = test_int ())) ABORT (t);\r |
| 685 | rlog = 0; /* clear log */ \r |
| 686 | incstorebp (fill, p1, pflgs);\r |
| 687 | AC(ac) = (AC(ac) & XFLGMASK) | ((AC(ac) - 1) & XLNTMASK);\r |
| 688 | }\r |
| 689 | rlog = 0;\r |
| 690 | return;\r |
| 691 | }\r |
| 692 | \r |
| 693 | /* Clean up after page fault\r |
| 694 | \r |
| 695 | Arguments:\r |
| 696 | logv = register change log\r |
| 697 | \r |
| 698 | For each register in logv, decrement the register's contents as\r |
| 699 | though it were a byte pointer. Note that the KS10 does <not>\r |
| 700 | do a full decrement calculation but merely adds S to P.\r |
| 701 | */\r |
| 702 | \r |
| 703 | void xtcln (int32 logv)\r |
| 704 | {\r |
| 705 | int32 p, reg;\r |
| 706 | \r |
| 707 | while (logv) {\r |
| 708 | XT_REMRLOG (reg, logv); /* get next reg */\r |
| 709 | if ((reg >= 0) && (reg < AC_NUM)) {\r |
| 710 | p = GET_P (AC(reg)) + GET_S (AC(reg)); /* get p + s */\r |
| 711 | AC(reg) = PUT_P (AC(reg), p); /* p <- p + s */\r |
| 712 | }\r |
| 713 | }\r |
| 714 | return;\r |
| 715 | }\r |