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