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