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