Commit | Line | Data |
---|---|---|
196ba1fc PH |
1 | /* pdp11_kg.c - Communications Arithmetic Option KG11-A\r |
2 | \r | |
3 | Copyright (c) 2007-2008, John A. Dundas III\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 the author 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 the author.\r | |
25 | \r | |
26 | kg KG11-A Communications Arithmetic Option (M7251)\r | |
27 | \r | |
28 | 08-Jan-08 JAD First public release integrated with SIMH V3.7-3.\r | |
29 | 09-Dec-07 JAD SIMH-style debugging.\r | |
30 | Finished validating against real hardware.\r | |
31 | Support for up to 8 units, the maximum.\r | |
32 | Keep all module data in the UNIT structure.\r | |
33 | Clean up bit and mask definitions.\r | |
34 | 01-Dec-07 JAD Now work on the corner cases that the\r | |
35 | diagnostic does not check.\r | |
36 | CLR does not clear the QUO bit.\r | |
37 | Correct SR write logic.\r | |
38 | 29-Nov-07 JAD Original implementation and testing based on\r | |
39 | an idea from 07-Jul-03. Passes the ZKGAB0\r | |
40 | diagnostic.\r | |
41 | \r | |
42 | Information necessary to create this simulation was gathered from\r | |
43 | a number of sources including:\r | |
44 | \r | |
45 | KG11-A Exclusive-OR and CRC block check manual, DEC-11-HKGAA-B-D\r | |
46 | <http://www.computer.museum.uq.edu.au/pdf/DEC-11-HKGAA-B-D%20KG11-A%20Exclusive-OR%20and%20CRC%20Block%20Check%20Manual.pdf>\r | |
47 | Maintenance print set\r | |
48 | <http://bitsavers.org/pdf/dec/unibus/KG11A_EngrDrws.pdf>\r | |
49 | A Painless Guide to CRC Error Detection Algorithms, Ross N. Williams\r | |
50 | <http://www.ross.net/crc/download/crc_v3.txt">\r | |
51 | \r | |
52 | The original PDP-11 instruction set, as implemented in the /20,\r | |
53 | /15, /10, and /5, did not include XOR. [One of the differences\r | |
54 | tables incorrectly indicates the /04 does not implement this\r | |
55 | instruction.] This device implements XOR, XORB, and a variety of\r | |
56 | CRCs.\r | |
57 | \r | |
58 | The maintenance prints indicate that the device was probably available\r | |
59 | starting in late 1971. May need to check further. The first edition\r | |
60 | of the manual was May 1972.\r | |
61 | \r | |
62 | The device was still sold at least as late as mid-1982 according\r | |
63 | to the PDP-11 Systems and Options Summary. RSTS/E included support\r | |
64 | for up to 8 units in support of the 2780 emulation or for use with\r | |
65 | DP11, DU11, or DUP11. The device appears to have been retired by\r | |
66 | 1983-03, and possibly earlier.\r | |
67 | \r | |
68 | I/O Page Registers\r | |
69 | \r | |
70 | SR 7707x0 (read-write) status\r | |
71 | BCC 7707x2 (read-only) BCC (block check character)\r | |
72 | DR 7707x4 (write-only) data\r | |
73 | \r | |
74 | Vector: none\r | |
75 | \r | |
76 | Priority: none\r | |
77 | \r | |
78 | The KG11-A is a programmed-I/O, non-interrupting device. Therefore\r | |
79 | no vector or bus request level are necessary. It is a Unibus device\r | |
80 | but since it does not address memory itself (it only presents\r | |
81 | registers in the I/O page) it is compatible with extended Unibus\r | |
82 | machines (22-bit) as well as traditional Unibus.\r | |
83 | \r | |
84 | Implements 5 error detection codes:\r | |
85 | LRC-8\r | |
86 | LRC-16\r | |
87 | CRC-12\r | |
88 | CRC-16\r | |
89 | CRC-CCITT\r | |
90 | */\r | |
91 | \r | |
92 | #if !defined (VM_PDP11)\r | |
93 | #error "KG11 is not supported!"\r | |
94 | #endif\r | |
95 | #include "pdp11_defs.h"\r | |
96 | \r | |
97 | extern FILE *sim_deb;\r | |
98 | extern REG cpu_reg[];\r | |
99 | extern int32 R[];\r | |
100 | \r | |
101 | #ifndef KG_UNITS\r | |
102 | #define KG_UNITS (8)\r | |
103 | #endif\r | |
104 | \r | |
105 | /* Control and Status Register */\r | |
106 | \r | |
107 | #define KGSR_V_QUO (8) /* RO */\r | |
108 | #define KGSR_V_DONE (7) /* RO */\r | |
109 | #define KGSR_V_SEN (6) /* R/W shift enable */\r | |
110 | #define KGSR_V_STEP (5) /* W */\r | |
111 | #define KGSR_V_CLR (4) /* W */\r | |
112 | #define KGSR_V_DDB (3) /* R/W double data byte */\r | |
113 | #define KGSR_V_CRCIC (2) /* R/W */\r | |
114 | #define KGSR_V_LRC (1) /* R/W */\r | |
115 | #define KGSR_V_16 (0) /* R/W */\r | |
116 | \r | |
117 | #define KGSR_M_QUO (1u << KGSR_V_QUO)\r | |
118 | #define KGSR_M_DONE (1u << KGSR_V_DONE)\r | |
119 | #define KGSR_M_SEN (1u << KGSR_V_SEN)\r | |
120 | #define KGSR_M_STEP (1u << KGSR_V_STEP)\r | |
121 | #define KGSR_M_CLR (1u << KGSR_V_CLR)\r | |
122 | #define KGSR_M_DDB (1u << KGSR_V_DDB)\r | |
123 | #define KGSR_M_CRCIC (1u << KGSR_V_CRCIC)\r | |
124 | #define KGSR_M_LRC (1u << KGSR_V_LRC)\r | |
125 | #define KGSR_M_16 (1u << KGSR_V_16)\r | |
126 | \r | |
127 | #define KG_SR_RDMASK (KGSR_M_QUO | KGSR_M_DONE | KGSR_M_SEN | KGSR_M_DDB | \\r | |
128 | KGSR_M_CRCIC | KGSR_M_LRC | KGSR_M_16)\r | |
129 | #define KG_SR_WRMASK (KGSR_M_SEN | KGSR_M_DDB | KGSR_M_CRCIC | \\r | |
130 | KGSR_M_LRC | KGSR_M_16)\r | |
131 | \r | |
132 | #define KG_SR_POLYMASK (KGSR_M_CRCIC|KGSR_M_LRC|KGSR_M_16)\r | |
133 | \r | |
134 | /* Unit structure redefinitions */\r | |
135 | #define SR u3\r | |
136 | #define BCC u4\r | |
137 | #define DR u5\r | |
138 | #define PULSCNT u6\r | |
139 | \r | |
140 | #define POLY_LRC8 (0x0008)\r | |
141 | #define POLY_LRC16 (0x0080)\r | |
142 | #define POLY_CRC12 (0x0f01)\r | |
143 | #define POLY_CRC16 (0xa001)\r | |
144 | #define POLY_CCITT (0x8408)\r | |
145 | \r | |
146 | static const struct {\r | |
147 | uint16 poly;\r | |
148 | uint16 pulses;\r | |
149 | const char * const name;\r | |
150 | } config[] = {\r | |
151 | /* DDB=0 */\r | |
152 | { POLY_CRC12, 6, "CRC-12" },\r | |
153 | { POLY_CRC16, 8, "CRC-16" },\r | |
154 | { POLY_LRC8, 8, "LRC-8" },\r | |
155 | { POLY_LRC16, 8, "LRC-16" },\r | |
156 | { 0, 0, "undefined" },\r | |
157 | { POLY_CCITT, 8, "CRC-CCITT" },\r | |
158 | { 0, 0, "undefined" },\r | |
159 | { 0, 0, "undefined" },\r | |
160 | /* DDB=1 */\r | |
161 | { POLY_CRC12, 12, "CRC-12" },\r | |
162 | { POLY_CRC16, 16, "CRC-16" },\r | |
163 | { POLY_LRC8, 16, "LRC-8" },\r | |
164 | { POLY_LRC16, 16, "LRC-16" },\r | |
165 | { 0, 0, "undefined" },\r | |
166 | { POLY_CCITT, 16, "CRC-CCITT" },\r | |
167 | { 0, 0, "undefined" },\r | |
168 | { 0, 0, "undefined" }\r | |
169 | };\r | |
170 | \r | |
171 | /* Forward declarations */\r | |
172 | \r | |
173 | static t_stat kg_rd (int32 *, int32, int32);\r | |
174 | static t_stat kg_wr (int32, int32, int32);\r | |
175 | static t_stat kg_reset (DEVICE *);\r | |
176 | static void do_poly (int, t_bool);\r | |
177 | static t_stat set_units (UNIT *, int32, char *, void *);\r | |
178 | \r | |
179 | /* 16-bit rotate right */\r | |
180 | \r | |
181 | #define ROR(n,v) (((v >> n) & DMASK) | (v << (16 - n)) & DMASK)\r | |
182 | \r | |
183 | /* 8-bit rotate right */\r | |
184 | \r | |
185 | #define RORB(n,v) (((v & 0377) >> n) | ((v << (8 - n)) & 0377))\r | |
186 | \r | |
187 | /* KG data structures\r | |
188 | \r | |
189 | kg_dib KG PDP-11 device information block\r | |
190 | kg_unit KG unit descriptor\r | |
191 | kg_reg KG register list\r | |
192 | kg_mod KG modifiers table\r | |
193 | kg_debug KG debug names table\r | |
194 | kg_dev KG device descriptor\r | |
195 | */\r | |
196 | \r | |
197 | static DIB kg_dib = {\r | |
198 | IOBA_KG,\r | |
199 | (IOLN_KG + 2) * KG_UNITS,\r | |
200 | &kg_rd,\r | |
201 | &kg_wr,\r | |
202 | 0, 0, 0, { NULL }\r | |
203 | };\r | |
204 | \r | |
205 | static UNIT kg_unit[] = {\r | |
206 | { UDATA (NULL, 0, 0) },\r | |
207 | { UDATA (NULL, UNIT_DISABLE + UNIT_DIS, 0) },\r | |
208 | { UDATA (NULL, UNIT_DISABLE + UNIT_DIS, 0) },\r | |
209 | { UDATA (NULL, UNIT_DISABLE + UNIT_DIS, 0) },\r | |
210 | { UDATA (NULL, UNIT_DISABLE + UNIT_DIS, 0) },\r | |
211 | { UDATA (NULL, UNIT_DISABLE + UNIT_DIS, 0) },\r | |
212 | { UDATA (NULL, UNIT_DISABLE + UNIT_DIS, 0) },\r | |
213 | { UDATA (NULL, UNIT_DISABLE + UNIT_DIS, 0) },\r | |
214 | };\r | |
215 | \r | |
216 | static const REG kg_reg[] = {\r | |
217 | { ORDATA (SR0, kg_unit[0].SR, 16) },\r | |
218 | { ORDATA (SR1, kg_unit[1].SR, 16) },\r | |
219 | { ORDATA (SR2, kg_unit[2].SR, 16) },\r | |
220 | { ORDATA (SR3, kg_unit[3].SR, 16) },\r | |
221 | { ORDATA (SR4, kg_unit[4].SR, 16) },\r | |
222 | { ORDATA (SR5, kg_unit[5].SR, 16) },\r | |
223 | { ORDATA (SR6, kg_unit[6].SR, 16) },\r | |
224 | { ORDATA (SR7, kg_unit[7].SR, 16) },\r | |
225 | { ORDATA (BCC0, kg_unit[0].BCC, 16) },\r | |
226 | { ORDATA (BCC1, kg_unit[1].BCC, 16) },\r | |
227 | { ORDATA (BCC2, kg_unit[2].BCC, 16) },\r | |
228 | { ORDATA (BCC3, kg_unit[3].BCC, 16) },\r | |
229 | { ORDATA (BCC4, kg_unit[4].BCC, 16) },\r | |
230 | { ORDATA (BCC5, kg_unit[5].BCC, 16) },\r | |
231 | { ORDATA (BCC6, kg_unit[6].BCC, 16) },\r | |
232 | { ORDATA (BCC7, kg_unit[7].BCC, 16) },\r | |
233 | { ORDATA (DR0, kg_unit[0].DR, 16) },\r | |
234 | { ORDATA (DR1, kg_unit[1].DR, 16) },\r | |
235 | { ORDATA (DR2, kg_unit[2].DR, 16) },\r | |
236 | { ORDATA (DR3, kg_unit[3].DR, 16) },\r | |
237 | { ORDATA (DR4, kg_unit[4].DR, 16) },\r | |
238 | { ORDATA (DR5, kg_unit[5].DR, 16) },\r | |
239 | { ORDATA (DR6, kg_unit[6].DR, 16) },\r | |
240 | { ORDATA (DR7, kg_unit[7].DR, 16) },\r | |
241 | { ORDATA (PULSCNT0, kg_unit[0].PULSCNT, 16) },\r | |
242 | { ORDATA (PULSCNT1, kg_unit[1].PULSCNT, 16) },\r | |
243 | { ORDATA (PULSCNT2, kg_unit[2].PULSCNT, 16) },\r | |
244 | { ORDATA (PULSCNT3, kg_unit[3].PULSCNT, 16) },\r | |
245 | { ORDATA (PULSCNT4, kg_unit[4].PULSCNT, 16) },\r | |
246 | { ORDATA (PULSCNT5, kg_unit[5].PULSCNT, 16) },\r | |
247 | { ORDATA (PULSCNT6, kg_unit[6].PULSCNT, 16) },\r | |
248 | { ORDATA (PULSCNT7, kg_unit[7].PULSCNT, 16) },\r | |
249 | { ORDATA (DEVADDR, kg_dib.ba, 32), REG_HRO },\r | |
250 | { NULL }\r | |
251 | };\r | |
252 | \r | |
253 | static const MTAB kg_mod[] = {\r | |
254 | { MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL, NULL, &show_addr, NULL },\r | |
255 | { MTAB_XTD|MTAB_VDV, 0, NULL, "UNITS=0..8", &set_units, NULL, NULL },\r | |
256 | { 0 }\r | |
257 | };\r | |
258 | \r | |
259 | #define DBG_REG (01)\r | |
260 | #define DBG_POLY (02)\r | |
261 | #define DBG_CYCLE (04)\r | |
262 | \r | |
263 | static const DEBTAB kg_debug[] = {\r | |
264 | {"REG", DBG_REG},\r | |
265 | {"POLY", DBG_POLY},\r | |
266 | {"CYCLE", DBG_CYCLE},\r | |
267 | {0},\r | |
268 | };\r | |
269 | \r | |
270 | DEVICE kg_dev = {\r | |
271 | "KG", (UNIT *) &kg_unit, (REG *) kg_reg, (MTAB *) kg_mod,\r | |
272 | KG_UNITS, 8, 16, 2, 8, 16,\r | |
273 | NULL, /* examine */\r | |
274 | NULL, /* deposit */\r | |
275 | &kg_reset, /* reset */\r | |
276 | NULL, /* boot */\r | |
277 | NULL, /* attach */\r | |
278 | NULL, /* detach */\r | |
279 | &kg_dib,\r | |
280 | DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_DEBUG,\r | |
281 | 0, /* debug control */\r | |
282 | (DEBTAB *) &kg_debug, /* debug flags */\r | |
283 | NULL, /* memory size chage */\r | |
284 | NULL /* logical name */\r | |
285 | };\r | |
286 | \f /* KG I/O address routines */\r | |
287 | \r | |
288 | static t_stat kg_rd (int32 *data, int32 PA, int32 access)\r | |
289 | {\r | |
290 | int unit = (PA >> 3) & 07;\r | |
291 | \r | |
292 | if ((unit >= KG_UNITS) || (kg_unit[unit].flags & UNIT_DIS))\r | |
293 | return (SCPE_NXM);\r | |
294 | switch ((PA >> 1) & 03) {\r | |
295 | \r | |
296 | case 00: /* SR */\r | |
297 | if (DEBUG_PRI(kg_dev, DBG_REG))\r | |
298 | fprintf (sim_deb, ">>KG%d: rd SR %06o, PC %06o\n",\r | |
299 | unit, kg_unit[unit].SR, PC);\r | |
300 | *data = kg_unit[unit].SR & KG_SR_RDMASK;\r | |
301 | break;\r | |
302 | \r | |
303 | case 01: /* BCC */\r | |
304 | if (DEBUG_PRI(kg_dev, DBG_REG))\r | |
305 | fprintf (sim_deb, ">>KG%d rd BCC %06o, PC %06o\n",\r | |
306 | unit, kg_unit[unit].BCC, PC);\r | |
307 | *data = kg_unit[unit].BCC & DMASK;\r | |
308 | break;\r | |
309 | \r | |
310 | case 02: /* DR */\r | |
311 | break;\r | |
312 | \r | |
313 | default:\r | |
314 | break;\r | |
315 | }\r | |
316 | return (SCPE_OK);\r | |
317 | }\r | |
318 | \r | |
319 | static t_stat kg_wr (int32 data, int32 PA, int32 access)\r | |
320 | {\r | |
321 | int setup;\r | |
322 | int unit = (PA >> 3) & 07;\r | |
323 | \r | |
324 | if ((unit >= KG_UNITS) || (kg_unit[unit].flags & UNIT_DIS))\r | |
325 | return (SCPE_NXM);\r | |
326 | switch ((PA >> 1) & 03) {\r | |
327 | \r | |
328 | case 00: /* SR */\r | |
329 | if (access == WRITEB)\r | |
330 | data = (PA & 1) ?\r | |
331 | (kg_unit[unit].SR & 0377) | (data << 8) :\r | |
332 | (kg_unit[unit].SR & ~0377) | data;\r | |
333 | if (DEBUG_PRI(kg_dev, DBG_REG))\r | |
334 | fprintf (sim_deb, ">>KG%d: wr SR %06o, PC %06o\n",\r | |
335 | unit, data, PC);\r | |
336 | if (data & KGSR_M_CLR) {\r | |
337 | kg_unit[unit].PULSCNT = 0; /* not sure about this */\r | |
338 | kg_unit[unit].BCC = 0;\r | |
339 | kg_unit[unit].SR |= KGSR_M_DONE;\r | |
340 | }\r | |
341 | setup = (kg_unit[unit].SR & 017) ^ (data & 017);\r | |
342 | kg_unit[unit].SR = (kg_unit[unit].SR & ~KG_SR_WRMASK) |\r | |
343 | (data & KG_SR_WRMASK);\r | |
344 | /* if low 4b changed, reset C1 & C2 */\r | |
345 | if (setup) {\r | |
346 | kg_unit[unit].PULSCNT = 0;\r | |
347 | if (DEBUG_PRI(kg_dev, DBG_POLY))\r | |
348 | fprintf (sim_deb, ">>KG%d poly %s %d\n",\r | |
349 | unit, config[data & 017].name, config[data & 017].pulses);\r | |
350 | }\r | |
351 | if (data & KGSR_M_SEN)\r | |
352 | break;\r | |
353 | if (data & KGSR_M_STEP) {\r | |
354 | do_poly (unit, TRUE);\r | |
355 | break;\r | |
356 | }\r | |
357 | break;\r | |
358 | \r | |
359 | case 01: /* BCC */\r | |
360 | break; /* ignored */\r | |
361 | \r | |
362 | case 02: /* DR */\r | |
363 | if (access == WRITEB)\r | |
364 | data = (PA & 1) ?\r | |
365 | (kg_unit[unit].DR & 0377) | (data << 8) :\r | |
366 | (kg_unit[unit].DR & ~0377) | data;\r | |
367 | kg_unit[unit].DR = data & DMASK;\r | |
368 | if (DEBUG_PRI(kg_dev, DBG_REG))\r | |
369 | fprintf (sim_deb, ">>KG%d: wr DR %06o, data %06o, PC %06o\n",\r | |
370 | unit, kg_unit[unit].DR, data, PC);\r | |
371 | kg_unit[unit].SR &= ~KGSR_M_DONE;\r | |
372 | \r | |
373 | /* In a typical device, this is normally where we would use sim_activate()\r | |
374 | to initiate an I/O to be completed later. The KG is a little\r | |
375 | different. When it was first introduced, it's computation operation\r | |
376 | completed before another instruction could execute (on early PDP-11s),\r | |
377 | and software often took "advantage" of this fact by not bothering\r | |
378 | to check the status of the DONE bit. In reality, the execution\r | |
379 | time of the polynomial is dependent upon the width of the poly; if\r | |
380 | 8 bits 1us, if 16 bits, 2us. Since known existing software will\r | |
381 | break if we actually defer the computation, it is performed immediately\r | |
382 | instead. However this could easily be made into a run-time option,\r | |
383 | if there were software to validate correct operation. */\r | |
384 | \r | |
385 | if (kg_unit[unit].SR & KGSR_M_SEN)\r | |
386 | do_poly (unit, FALSE);\r | |
387 | break;\r | |
388 | \r | |
389 | default:\r | |
390 | break;\r | |
391 | }\r | |
392 | return (SCPE_OK);\r | |
393 | }\r | |
394 | \r | |
395 | /* KG reset */\r | |
396 | \r | |
397 | static t_stat kg_reset (DEVICE *dptr)\r | |
398 | {\r | |
399 | int i;\r | |
400 | \r | |
401 | if (DEBUG_PRI(kg_dev, DBG_REG))\r | |
402 | fprintf (sim_deb, ">>KG: reset PC %06o\n", PC);\r | |
403 | for (i = 0; i < KG_UNITS; i++) {\r | |
404 | kg_unit[i].SR = KGSR_M_DONE;\r | |
405 | kg_unit[i].BCC = 0;\r | |
406 | kg_unit[i].PULSCNT = 0;\r | |
407 | }\r | |
408 | return (SCPE_OK);\r | |
409 | }\r | |
410 | \r | |
411 | static void cycleOneBit (int unit)\r | |
412 | {\r | |
413 | int quo;\r | |
414 | \r | |
415 | if (DEBUG_PRI(kg_dev, DBG_CYCLE))\r | |
416 | fprintf (sim_deb, ">>KG%d: cycle s BCC %06o DR %06o\n",\r | |
417 | unit, kg_unit[unit].BCC, kg_unit[unit].DR);\r | |
418 | if (kg_unit[unit].SR & KGSR_M_DONE)\r | |
419 | return;\r | |
420 | if ((kg_unit[unit].SR & KG_SR_POLYMASK) == 0)\r | |
421 | kg_unit[unit].BCC = (kg_unit[unit].BCC & 077) |\r | |
422 | ((kg_unit[unit].BCC >> 2) & 07700);\r | |
423 | kg_unit[unit].SR &= ~KGSR_M_QUO;\r | |
424 | quo = (kg_unit[unit].BCC & 01) ^ (kg_unit[unit].DR & 01);\r | |
425 | kg_unit[unit].BCC = (kg_unit[unit].BCC & ~01) | quo;\r | |
426 | if (kg_unit[unit].SR & KGSR_M_LRC)\r | |
427 | kg_unit[unit].BCC = (kg_unit[unit].SR & KGSR_M_16) ?\r | |
428 | ROR(1, kg_unit[unit].BCC) :\r | |
429 | RORB(1, kg_unit[unit].BCC);\r | |
430 | else\r | |
431 | kg_unit[unit].BCC = (kg_unit[unit].BCC & 01) ?\r | |
432 | (kg_unit[unit].BCC >> 1) ^ config[kg_unit[unit].SR & 07].poly :\r | |
433 | kg_unit[unit].BCC >> 1;\r | |
434 | kg_unit[unit].DR >>= 1;\r | |
435 | kg_unit[unit].SR |= quo << KGSR_V_QUO;\r | |
436 | if ((kg_unit[unit].SR & KG_SR_POLYMASK) == 0)\r | |
437 | kg_unit[unit].BCC = (kg_unit[unit].BCC & 077) |\r | |
438 | ((kg_unit[unit].BCC & 07700) << 2);\r | |
439 | kg_unit[unit].PULSCNT++;\r | |
440 | if (kg_unit[unit].PULSCNT >= config[kg_unit[unit].SR & 017].pulses)\r | |
441 | kg_unit[unit].SR |= KGSR_M_DONE;\r | |
442 | if (DEBUG_PRI(kg_dev, DBG_CYCLE))\r | |
443 | fprintf (sim_deb, ">>KG%d: cycle e BCC %06o DR %06o\n",\r | |
444 | unit, kg_unit[unit].BCC, kg_unit[unit].DR);\r | |
445 | }\r | |
446 | \r | |
447 | static void do_poly (int unit, t_bool step)\r | |
448 | {\r | |
449 | if (kg_unit[unit].SR & KGSR_M_DONE)\r | |
450 | return;\r | |
451 | if (step)\r | |
452 | cycleOneBit (unit);\r | |
453 | else {\r | |
454 | while (!(kg_unit[unit].SR & KGSR_M_DONE))\r | |
455 | cycleOneBit (unit);\r | |
456 | }\r | |
457 | }\r | |
458 | \r | |
459 | static t_stat set_units (UNIT *u, int32 val, char *s, void *desc)\r | |
460 | {\r | |
461 | int32 i, units;\r | |
462 | t_stat stat;\r | |
463 | \r | |
464 | if (s == NULL)\r | |
465 | return (SCPE_ARG);\r | |
466 | units = get_uint (s, 10, KG_UNITS, &stat);\r | |
467 | if (stat != SCPE_OK)\r | |
468 | return (stat);\r | |
469 | for (i = 0; i < KG_UNITS; i++) {\r | |
470 | if (i < units)\r | |
471 | kg_unit[i].flags &= ~UNIT_DIS;\r | |
472 | else\r | |
473 | kg_unit[i].flags |= UNIT_DIS;\r | |
474 | }\r | |
475 | kg_dev.numunits = units;\r | |
476 | return (SCPE_OK);\r | |
477 | }\r |