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