1 /*
2 * vim: filetype=c:tabstop=4:ai:expandtab
3 * SPDX-License-Identifier: ICU
4 * scspell-id: 8e66ce24-f62e-11ec-8690-80ee73e9b8e7
5 *
6 * ---------------------------------------------------------------------------
7 *
8 * Copyright (c) 2007-2013 Michael Mondy
9 * Copyright (c) 2012-2016 Harry Reed
10 * Copyright (c) 2013-2022 Charles Anthony
11 * Copyright (c) 2026 Eric Swenson
12 * Copyright (c) 2026 Jeffrey H. Johnson
13 * Copyright (c) 2021-2025 The DPS8M Development Team
14 *
15 * This software is made available under the terms of the ICU License.
16 * See the LICENSE.md file at the top-level directory of this distribution.
17 *
18 * ---------------------------------------------------------------------------
19 */
20
21 // IDCW Instruction 18-20 111
22 // TDCW Transfer 18-20 !111, 22-23 10
23 // IOTD IO Transfer and disconnect 18-20 !111, 22-23 00
24 // IOTP IO Transfer and proceed 18-20 !111, 22-23 01
25 // IONTP IO Non-Transfer and proceed 18-20 !111, 22-23 11
26
27 #if defined(IO_THREADZ)
28 extern __thread uint this_iom_idx;
29 extern __thread uint this_chan_num;
30 //extern __thread bool thisIOMHaveLock;
31 #endif
32
33 //typedef enum
34 //{
35 //cm_LPW_init_state, // No TDCWs encountered; state is:
36 //// PCW64 (pcw64_pge): on PAGE CHAN
37 //// PCW64 (pcw64_pge): off EXT MODE CHAN
38 //cm_real_LPW_real_DCW,
39 //cm_ext_LPW_real_DCW,
40 //cm_paged_LPW_seg_DCW
41 //} chanMode_t;
42
43 typedef enum chanStat
44 {
45 chanStatNormal = 0,
46 chanStatUnexpectedPCW = 1,
47 chanStatInvalidInstrPCW = 2,
48 chanStatIncorrectDCW = 3,
49 chanStatIncomplete = 4,
50 chanStatUnassigned = 5,
51 chanStatParityErrPeriph = 6,
52 chanStatParityErrBus = 7
53 } chanStat;
54
55 // Due to lack of documentation, chan_cmd is largely ignored
56 //
57 // iom_chan_control_words.incl.pl1
58 //
59 // SINGLE_RECORD init ("00"b3),
60 // NONDATA init ("02"b3),
61 // MULTIRECORD init ("06"b3),
62 // SINGLE_CHARACTER init ("10"b3)
63 //
64 // bound_tolts_/mtdsim_.pl1
65 //
66 // idcw.chan_cmd = "40"b3; /* otherwise set special cont. cmd */
67 //
68 // bound_io_tools/exercise_disk.pl1
69 //
70 // idcw.chan_cmd = INHIB_AUTO_RETRY; /* inhibit mpc auto retries */
71 // dcl INHIB_AUTO_RETRY bit (6) int static init ("010001"b); // 021
72 //
73 // poll_mpc.pl1:
74 // /* Build dcw list to get statistics from EURC MPC */
75 // idcw.chan_cmd = "41"b3; /* Indicate special controller command */
76 // /* Build dcw list to get configuration and statistics from DAU MSP */
77 // idcw.chan_cmd = "30"b3; /* Want list in dev# order */
78 //
79 // tape_ioi_io.pl1:
80 // idcw.chan_cmd = "03"b3; /* data security erase */
81 // dcw.chan_cmd = "30"b3; /* use normal values, auto-retry */
82
83 // iom_word_macros.incl.alm
84 //
85 // Channel control
86 #define CHAN_CTRL_TERMINATE 0
87 #define CHAN_CTRL_PROCEED 2
88 #define CHAN_CTRL_MARKER 3
89
90 // Channel command
91 #define CHAN_CMD_RECORD 0
92 #define CHAN_CMD_NONDATA 2
93 #define CHAN_CMD_MULTIRECORD 6
94 #define CHAN_CMD_CHARACTER 8
95
96 #define IS_IDCW(p) ((p)->DCW_18_20_CP == 07)
97 #define IS_NOT_IDCW(p) ((p)->DCW_18_20_CP != 07)
98 #define IS_TDCW(p) ((p)->DCW_18_20_CP != 7 && (p)->DDCW_22_23_TYPE == 2)
99 #define IS_IOTD(p) ((p)->DCW_18_20_CP != 7 && (p)->DDCW_22_23_TYPE == 0)
100 #define IS_IONTP(p) ((p)->DCW_18_20_CP != 7 && (p)->DDCW_22_23_TYPE == 3)
101
102 // exercise_disk.pl1
103 #define CHAN_CMD_INHIB_AUTO_RETRY 021
104 // load_mpc.pl1
105 #define CHAN_CMD_SPECIAL_CTLR 040
106 // poll_mpc.pl1
107 #define CHAN_CMD_DEV_ORDER 030
108 #define CHAN_CMD_SPECIAL_CTLR2 041
109 // tape_ioi_io.pl1
110 #define CHAN_CMD_DATA_SECURITY_ERASE 03
111 #define CHAN_CMD_NORM_AUTO_TRY 030
112
113 typedef volatile struct
114 {
115 // scratch pad
116
117 // packed LPW
118 word36 LPW;
119 // unpacked LPW
120 word18 LPW_DCW_PTR;
121 word1 LPW_18_RES;
122 word1 LPW_19_REL;
123 word1 LPW_20_AE;
124 word1 LPW_21_NC;
125 word1 LPW_22_TAL;
126 word1 LPW_23_REL;
127 word12 LPW_TALLY;
128
129 // packed LPWX
130 word36 LPWX;
131 // unpacked LPWX
132 word18 LPWX_BOUND; // MOD 2 (pg B16) 0-2^19; ie val = LPX_BOUND * 2
133 word18 LPWX_SIZE; // MOD 1 (pg B16) 0-2^18
134
135 // PCW_63_PTP indicates paging mode; indicates that a page table
136 // is available.
137 // XXX pg B11: cleared by a terminate interrupt service with the
138 // character size bit of the transaction command = 1. (bit 32)
139 // what is the 'transaction command.?
140
141 // packed PCW
142 word36 PCW0, PCW1;
143 // unpacked PCW
144 word6 PCW_CHAN;
145 word6 PCW_AE;
146 // Pg B2: "Absolute location (MOD 64) of the channels Page Table"
147 word18 PCW_PAGE_TABLE_PTR;
148 word1 PCW_63_PTP;
149 word1 PCW_64_PGE;
150 word1 PCW_65_AUX; // XXX
151 word1 PCW_21_MSK; // Sometimes called 'M' // see 3.2.2, pg 25
152
153 // packed DCW
154 word36 DCW;
155 // unpacked DCW
156 // TDCW only
157 word18 TDCW_DATA_ADDRESS;
158 word1 TDCW_34_RES;
159 word1 TDCW_35_REL;
160 // TDCW, PCW 64 = 0
161 word1 TDCW_33_EC;
162 // TDCW, PCW 64 = 1
163 word1 TDCW_31_SEG;
164 word1 TDCW_32_PDTA;
165 word1 TDCW_33_PDCW;
166 // IDCW only
167 word6 IDCW_DEV_CMD;
168 word6 IDCW_DEV_CODE;
169 word6 IDCW_AE;
170 word1 IDCW_EC;
171 word2 IDCW_CHAN_CTRL; // 0 terminate, 2 process, 3 marker
172 word6 IDCW_CHAN_CMD;
173 // POLTS sets this to one if there are IOTxes.
174 word6 IDCW_COUNT;
175 // DDCW only
176 /*word18*/ uint DDCW_ADDR; // Allow overflow detection
177 word12 DDCW_TALLY;
178 word2 DDCW_22_23_TYPE; // '2' indicates TDCW
179 // xDCW
180 word3 DCW_18_20_CP; // '7' indicates IDCW
181 // XXX pg 30; the indirect data service needs to use this.
182
183 word6 ADDR_EXT; // 3.2.2, 3.2.3.1
184 word1 SEG; // pg B21
185
186 enum { /* PGE */ cm1, cm2, cm3a, cm3b, cm4, cm5,
187 /* EXT */ cm1e, cm2e } chanMode;
188
189 // XXX CP XXXX
190 // "Specifies the positions of the first character with the first word
191 // of the block. The byte size, defined by the channel, determines
192 // what CP values are valid/
193 // 6 bit: 0-5; 9 bit: 0-4; 18 bit: 0-1; 36 bit: 0-6
194 //
195 // For word channels, CP is sent to the channel during list service,
196 // and is zeros when placed in the mailbox for subsequent data
197 // services to the channel.
198 //
199 // [CAC: I think that this can be elided. To implement correctly,
200 // iom_list_service and/or doPayloadChannel would have to know the
201 // word or sub-word functionality of the channel. But it would
202 // be simpler to let the device handler just access the CP data,
203 // and make it's own decisions about "zeros". After all, it is
204 // not clear what a non-zero CP means for a word channel.]
205 //
206 // For sub-word channels which depend on IOM Central for packing and
207 // unpacking words, [IOM Central uses and updates the CP to access
208 // sub-words].
209 //
210 // [CAC: Again, I think that this can be elided. It is simpler to
211 // to have the device handler pack and unpack.]
212 //
213
214 // LPW addressing mode
215
216 //enum { LPW_REAL, LPW_EXT, LPW_PAGED, LPW_SEG } lpwAddrMode;
217
218 // pg B2: "Scratchpad area for two Page Table Words ... one
219 // for the DCW List (PTW-LPW) and one for the data (PTW-DCW).
220
221 // PTW format: (pg B8)
222 // 4-17: Address of page table, mod 64
223 // 31: WRC: Write control bit (1: page may be written)
224 // 32: HSE: Housekeeping
225 // 33: PGP: Page present
226 // To read or write PGP must be 1
227 // To write, WRC must be 1, HSE 0; system fault 15 on fail
228 // pg b8: PTWs are used iff (indirect store and LPw 23 (segmented)), or
229 // direct store.
230 //
231 // ADDR 0-13 <- PTW 4-17
232 // 14-23 <- LPW 8-17; DCW 8-17; direct channel address 14-23
233
234 word36 PTW_DCW; // pg B8.
235 word36 PTW_LPW; // pg B6.
236
237 // pg b11 defines two PTW flags to indicate the validity of the
238 // PTW_DCW and PTW_LPW; it is simpler to simply always fetch
239 // the PTWs on demand.
240
241 // flag
242 //chanMode_t chanMode;
243
244 // true if the DCW is from a PCW
245 bool isPCW;
246
247 // Information accumulated for status service.
248 word12 stati;
249 uint dev_code;
250 // Initialized to IDCW_COUNT; decremented when a IDCW that expects an IOTx is processed by the channel.
251 // XXX POLTS console code drives this; if it turns out to be common across channels, the decrement should
252 // be moved into the IOM.
253 word6 recordResidue;
254 word12 tallyResidue;
255 word3 charPos;
256 bool isRead;
257 // isOdd can be ignored; see https://ringzero.wikidot.com/wiki:cac-2015-10-22
258 // bool isOdd;
259 bool initiate;
260
261 chanStat chanStatus;
262
263 bool lsFirst;
264
265 bool wasTDCW;
266
267 bool masked;
268
269 bool in_use;
270
271 bool start;
272
273 } iom_chan_data_t;
274
275 extern iom_chan_data_t iom_chan_data [N_IOM_UNITS_MAX] [MAX_CHANNELS];
276
277 extern DEVICE iom_dev;
278
279 // Indirect data service data type
280 typedef enum
281 {
282 idsTypeW36 // Incoming data is array of word36
283 } idsType;
284
285 typedef enum
286 {
287 direct_load,
288 direct_store,
289 direct_read_clear,
290 } iom_direct_data_service_op;
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328 #define IOM_MBX_LPW 0
329 #define IOM_MBX_LPWX 1
330 #define IOM_MBX_SCW 2
331 #define IOM_MBX_DCW 3
332
333 /* From AN70-1 May84
334 * ... The IOM determines an interrupt
335 * number. (The interrupt number is a five bit value, from 0 to 31.
336 * The high order bits are the interrupt level.
337 *
338 * 0 - system fault
339 * 1 - terminate
340 * 2 - marker
341 * 3 - special
342 *
343 * The low order three bits determines the IOM and IOM channel
344 * group.
345 *
346 * 0 - IOM 0 channels 32-63
347 * 1 - IOM 1 channels 32-63
348 * 2 - IOM 2 channels 32-63
349 * 3 - IOM 3 channels 32-63
350 * 4 - IOM 0 channels 0-31
351 * 5 - IOM 1 channels 0-31
352 * 6 - IOM 2 channels 0-31
353 * 7 - IOM 3 channels 0-31
354 *
355 * 3 3 3 3 3
356 * 1 2 3 4 5
357 * ---------------------
358 * | pic | group | iom |
359 * -----------------------------
360 * 2 1 2
361 */
362
363 enum iomImwPics
364 {
365 imwSystemFaultPic = 0,
366 imwTerminatePic = 1,
367 imwMarkerPic = 2,
368 imwSpecialPic = 3
369 };
370
371 int send_general_interrupt (uint iom_unit_idx, uint chan, enum iomImwPics pic);
372
373 int send_special_interrupt (uint iom_unit_idx, uint chanNum, uint devCode,
374 word8 status0, word8 status1);
375 //
376 // iom_cmd_t returns:
377 //
378 // 0: ok
379 // 1; ignored cmd, drop connect.
380 // 2: did command, don't do DCW list
381 // 3; command pending, don't sent terminate interrupt
382 // -1: error
383
384 //#define IOM_CMD_OK 0
385 //#define IOM_CMD_IGNORED 1
386 //#define IOM_CMD_NO_DCW 2
387 //#define IOM_CMD_PENDING 3
388 //#define IOM_CMD_ERROR -1
389
390 typedef enum
391 {
392 IOM_CMD_ERROR = -1,
393 IOM_CMD_PROCEED = 0,
394 IOM_CMD_RESIDUE,
395 IOM_CMD_DISCONNECT,
396 IOM_CMD_PENDING
397 } iom_cmd_rc_t;
398
399 typedef iom_cmd_rc_t iom_cmd_t (uint iom_unit_idx, uint chan);
400 int iom_list_service (uint iom_unit_idx, uint chan,
401 bool * ptro, bool * sendp, bool * uffp);
402 int send_terminate_interrupt (uint iom_unit_idx, uint chanNum);
403 void iom_interrupt (uint scuUnitNum, uint iom_unit_idx);
404 void iom_direct_data_service (uint iom_unit_idx, uint chan, word24 daddr, word36 * data,
405 iom_direct_data_service_op op);
406 void iom_indirect_data_service (uint iom_unit_idx, uint chan, word36 * data,
407 uint * cnt, bool write);
408 void iom_init (void);
409 int send_marker_interrupt (uint iom_unit_idx, int chan);
410 void iom_advance_lpw (uint iom_unit_idx, uint chan);
411 int iom_continue_channel (uint iom_unit_idx, uint chan);
412 #if defined(PANEL68)
413 void do_boot (void);
414 #endif
415 #if defined(IO_THREADZ)
416 void * iom_thread_main (void * arg);
417 void * chan_thread_main (void * arg);
418 #endif
419 void iom_core_read (uint iom_unit_idx, word24 addr, word36 *data, UNUSED const char * ctx);
420 void iom_core_read2 (uint iom_unit_idx, word24 addr, word36 *even, word36 *odd, UNUSED const char * ctx);
421 void iom_core_write (uint iom_unit_idx, word24 addr, word36 data, UNUSED const char * ctx);
422 void iom_core_write2 (uint iom_unit_idx, word24 addr, word36 even, word36 odd, UNUSED const char * ctx);
423 void iom_core_read_lock (uint iom_unit_idx, word24 addr, word36 *data, UNUSED const char * ctx);
424 void iom_core_write_unlock (uint iom_unit_idx, word24 addr, word36 data, UNUSED const char * ctx);
425 t_stat iom_unit_reset_idx (uint iom_unit_idx);
426
427 #if defined(IO_ASYNC_PAYLOAD_CHAN) || defined(IO_ASYNC_PAYLOAD_CHAN_THREAD)
428 void iomProcess (void);
429 #endif
430
431 char iomChar (uint iomUnitIdx);
432 #if defined(TESTING)
433 void dumpDCW (word36 DCW, word1 LPW_23_REL);
434 #endif