1 /*
2 * Copyright (c) 2007-2013 Michael Mondy
3 * Copyright (c) 2012-2016 Harry Reed
4 * Copyright (c) 2013-2016 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 #include <stdio.h>
15 #include <ctype.h>
16 #include <unistd.h>
17
18 #include "dps8.h"
19 #include "dps8_iom.h"
20 #include "dps8_urp.h"
21 #include "dps8_sys.h"
22 #include "dps8_faults.h"
23 #include "dps8_scu.h"
24 #include "dps8_cable.h"
25 #include "dps8_cpu.h"
26 #include "dps8_utils.h"
27
28 #define DBG_CTR 1
29
30 //-- // XXX We use this where we assume there is only one unit
31 //-- #define ASSUME0 0
32 //--
33
34 /*
35 * Copyright (c) 2007-2013 Michael Mondy
36 *
37 * This software is made available under the terms of the ICU
38 * License, version 1.8.1 or later. For more details, see the
39 * LICENSE.md file at the top-level directory of this distribution.
40 */
41
42 #define N_PRU_UNITS 1 // default
43
44 static struct urpState
45 {
46 enum urpMode
47 {
48 urpNoMode, urpSetDiag, urpInitRdData
49 } ioMode;
50 char deviceName [MAX_DEV_NAME_LEN];
51 } urpState [N_URP_UNITS_MAX];
52
53 #define UNIT_FLAGS ( UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | \
54 UNIT_IDLE )
55 UNIT urp_unit [N_URP_UNITS_MAX] = {
56 #ifdef NO_C_ELLIPSIS
57 { UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
58 { UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
59 { UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
60 { UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
61 { UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
62 { UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
63 { UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
64 { UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
65 { UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
66 { UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
67 { UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
68 { UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
69 { UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
70 { UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
71 { UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
72 { UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL }
73 #else
74 [0 ... N_URP_UNITS_MAX-1] = {
75 UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL
76 }
77 #endif
78 };
79
80 #define URPUNIT_NUM(uptr) ((uptr) - urp_unit)
81
82 static DEBTAB urp_dt [] =
83 {
84 { "NOTIFY", DBG_NOTIFY, NULL },
85 { "INFO", DBG_INFO, NULL },
86 { "ERR", DBG_ERR, NULL },
87 { "WARN", DBG_WARN, NULL },
88 { "DEBUG", DBG_DEBUG, NULL },
89 { "TRACE", DBG_TRACE, NULL },
90 { "ALL", DBG_ALL, NULL }, // don't move as it messes up DBG message
91 { NULL, 0, NULL }
92 };
93
urpShowUnits(UNUSED FILE * st,UNUSED UNIT * uptr,UNUSED int val,UNUSED const void * desc)94 static t_stat urpShowUnits (UNUSED FILE * st, UNUSED UNIT * uptr, UNUSED int val, UNUSED const void * desc)
95 {
96 sim_printf("Number of URPunits in system is %d\n", urp_dev.numunits);
97 return SCPE_OK;
98 }
99
urpSetUnits(UNUSED UNIT * uptr,UNUSED int32 value,const char * cptr,UNUSED void * desc)100 static t_stat urpSetUnits (UNUSED UNIT * uptr, UNUSED int32 value, const char * cptr, UNUSED void * desc)
101 {
102 if (! cptr)
103 return SCPE_ARG;
104 int n = atoi (cptr);
105 if (n < 1 || n > N_URP_UNITS_MAX)
106 return SCPE_ARG;
107 urp_dev.numunits = (uint32) n;
108 return SCPE_OK;
109 }
110
urpShowDeviceName(UNUSED FILE * st,UNIT * uptr,UNUSED int val,UNUSED const void * desc)111 static t_stat urpShowDeviceName (UNUSED FILE * st, UNIT * uptr, UNUSED int val, UNUSED const void * desc)
112 {
113 int n = (int) URPUNIT_NUM (uptr);
114 if (n < 0 || n >= N_URP_UNITS_MAX)
115 return SCPE_ARG;
116 sim_printf ("Unit record processor device name is %s\n", urpState[n].deviceName);
117 return SCPE_OK;
118 }
119
urpSetDeviceName(UNUSED UNIT * uptr,UNUSED int32 value,UNUSED const char * cptr,UNUSED void * desc)120 static t_stat urpSetDeviceName (UNUSED UNIT * uptr, UNUSED int32 value, UNUSED const char * cptr, UNUSED void * desc)
121 {
122 int n = (int) URPUNIT_NUM (uptr);
123 if (n < 0 || n >= N_URP_UNITS_MAX)
124 return SCPE_ARG;
125 if (cptr)
126 {
127 strncpy (urpState[n].deviceName, cptr, MAX_DEV_NAME_LEN - 1);
128 urpState[n].deviceName[MAX_DEV_NAME_LEN - 1] = 0;
129 }
130 else
131 urpState[n].deviceName [0] = 0;
132 return SCPE_OK;
133 }
134
135 #define UNIT_WATCH UNIT_V_UF
136
137 static MTAB urp_mod [] =
138 {
139 { UNIT_WATCH, 1, "WATCH", "WATCH", 0, 0, NULL, NULL },
140 { UNIT_WATCH, 0, "NOWATCH", "NOWATCH", 0, 0, NULL, NULL },
141 {
142 MTAB_XTD | MTAB_VDV | MTAB_NMO | MTAB_VALR, /* mask */
143 0, /* match */
144 "NUNITS", /* print string */
145 "NUNITS", /* match string */
146 urpSetUnits, /* validation routine */
147 urpShowUnits, /* display routine */
148 "Number of URPunits in the system", /* value descriptor */
149 NULL // Help
150 },
151 {
152 MTAB_XTD | MTAB_VUN | MTAB_VALR | MTAB_NC, /* mask */
153 0, /* match */
154 "NAME", /* print string */
155 "NAME", /* match string */
156 urpSetDeviceName, /* validation routine */
157 urpShowDeviceName, /* display routine */
158 "Set the device name", /* value descriptor */
159 NULL // help
160 },
161
162 { 0, 0, NULL, NULL, 0, 0, NULL, NULL }
163 };
164
urpReset(UNUSED DEVICE * dptr)165 static t_stat urpReset (UNUSED DEVICE * dptr)
166 {
167 return SCPE_OK;
168 }
169
170
171 DEVICE urp_dev = {
172 "URP", /* name */
173 urp_unit, /* units */
174 NULL, /* registers */
175 urp_mod, /* modifiers */
176 N_PRU_UNITS, /* #units */
177 10, /* address radix */
178 24, /* address width */
179 1, /* address increment */
180 8, /* data radix */
181 36, /* data width */
182 NULL, /* examine */
183 NULL, /* deposit */
184 urpReset, /* reset */
185 NULL, /* boot */
186 NULL, /* attach */
187 NULL, /* detach */
188 NULL, /* context */
189 DEV_DEBUG, /* flags */
190 0, /* debug control flags */
191 urp_dt, /* debug flag names */
192 NULL, /* memory size change */
193 NULL, /* logical name */
194 NULL, // help
195 NULL, // attach help
196 NULL, // attach context
197 NULL, // description
198 NULL
199 };
200
201 /*
202 * urp_init()
203 *
204 */
205
206 // Once-only initialization
207
urp_init(void)208 void urp_init (void)
209 {
210 memset (urpState, 0, sizeof (urpState));
211 }
212
213
urpCmd(uint iomUnitIdx,uint chan)214 static iom_cmd_rc_t urpCmd (uint iomUnitIdx, uint chan) {
215 iom_chan_data_t * p = & iom_chan_data [iomUnitIdx] [chan];
216 #ifdef TESTING
217 if_sim_debug (DBG_TRACE, & urp_dev) dumpDCW (p->DCW, 0);
218 #endif
219 uint ctlrUnitIdx = get_ctlr_idx (iomUnitIdx, chan);
220 uint devUnitIdx = cables->urp_to_urd[ctlrUnitIdx][p->IDCW_DEV_CODE].unit_idx;
221 //UNIT * unitp = & urp_unit [devUnitIdx];
222 //int urp_unit_num = (int) URPUNIT_NUM (unitp);
223 struct urpState * statep = & urpState[devUnitIdx];
224
225 // IDCW?
226 if (IS_IDCW (p)) {
227 // IDCW
228 statep->ioMode = urpNoMode;
229
230 switch (p->IDCW_DEV_CMD) {
231 case 000: // CMD 00 Request status
232 if_sim_debug (DBG_TRACE, & urp_dev) { sim_printf ("// URP Request Status\r\n"); }
233 sim_debug (DBG_DEBUG, & urp_dev, "%s: Request Status\n", __func__);
234 p->stati = 04000;
235 break;
236
237 case 006: // CMD 005 Initiate read data xfer (load_mpc.pl1)
238 if_sim_debug (DBG_TRACE, & urp_dev) { sim_printf ("// URP Initiate Read Data Xfer\r\n"); }
239 sim_debug (DBG_DEBUG, & urp_dev, "%s: Initiate Read Data Xfer\n", __func__);
240 statep->ioMode = urpInitRdData;
241 p->stati = 04000;
242 break;
243
244 // 011 punch binary
245 // 031 set diagnostic mode
246
247 case 031: // CMD 031 Set Diagnostic Mode (load_mpc.pl1)
248 if_sim_debug (DBG_TRACE, & urp_dev) { sim_printf ("// URP Set Diagnostic Mode\r\n"); }
249 sim_debug (DBG_DEBUG, & urp_dev, "%s: Set Diagnostic Mode\n", __func__);
250 statep->ioMode = urpSetDiag;
251 p->stati = 04000;
252 break;
253
254 case 040: // CMD 40 Reset status
255 if_sim_debug (DBG_TRACE, & urp_dev) { sim_printf ("// URP Reset Status\r\n"); }
256 sim_debug (DBG_DEBUG, & urp_dev, "%s: Reset Status\n", __func__);
257 p->stati = 04000;
258 p->isRead = false;
259 break;
260
261 default:
262 if_sim_debug (DBG_TRACE, & urp_dev) { sim_printf ("// URP unknown command %o\r\n", p->IDCW_DEV_CMD); }
263 p->stati = 04501; // cmd reject, invalid opcode
264 p->chanStatus = chanStatIncorrectDCW;
265 if (p->IDCW_DEV_CMD != 051) // ignore bootload console probe
266 sim_warn ("%s: URP unrecognized device command %02o\n", __func__, p->IDCW_DEV_CMD);
267 return IOM_CMD_ERROR;
268 } // switch IDCW_DEV_CMD
269
270 sim_debug (DBG_DEBUG, & urp_dev, "%s: stati %04o\n", __func__, p->stati);
271 return IOM_CMD_PROCEED;
272 } // if IDCW
273
274 // Not IDCW; TDCW are captured in IOM, so must be IOTD, IOTP or IOTNP
275 switch (statep->ioMode) {
276 case urpNoMode:
277 if_sim_debug (DBG_TRACE, & urp_dev) { sim_printf ("// URP IOT no mode\r\n"); }
278 //sim_printf ("%s: Unexpected IOTx\n", __func__);
279 //sim_warn ("%s: Unexpected IOTx\n", __func__);
280 //return IOM_CMD_ERROR;
281 break;
282
283 case urpSetDiag:
284 if_sim_debug (DBG_TRACE, & urp_dev) { sim_printf ("// URP IOT Set Diag\r\n"); }
285 // We don't use the DDCW, so just pretend we do. BUG
286 p->stati = 04000;
287 break;
288
289 case urpInitRdData:
290 if_sim_debug (DBG_TRACE, & urp_dev) { sim_printf ("// URP IOT Init Rd Data\r\n"); }
291 // We don't use the DDCW, so just pretend we do. BUG
292 p->stati = 04000;
293 break;
294
295 default:
296 if_sim_debug (DBG_TRACE, & urp_dev) { sim_printf ("// URP IOT unkown %d\r\n", statep->ioMode); }
297 sim_warn ("%s: Unrecognized ioMode %d\n", __func__, statep->ioMode);
298 return IOM_CMD_ERROR;
299 }
300 return IOM_CMD_PROCEED;
301 }
302
urp_iom_cmd(uint iomUnitIdx,uint chan)303 iom_cmd_rc_t urp_iom_cmd (uint iomUnitIdx, uint chan) {
304 iom_chan_data_t * p = & iom_chan_data [iomUnitIdx] [chan];
305 uint devCode = p->IDCW_DEV_CODE;
306 if (devCode == 0)
307 return urpCmd (iomUnitIdx, chan);
308 uint urpUnitIdx = cables->iom_to_ctlr[iomUnitIdx][chan].ctlr_unit_idx;
309 iom_cmd_t * cmd = cables->urp_to_urd[urpUnitIdx][devCode].iom_cmd;
310 if (! cmd) {
311 //sim_warn ("URP can't find device handler\n");
312 //return IOM_CMD_ERROR;
313 p->stati = 04502; // invalid device code
314 return IOM_CMD_DISCONNECT;
315 }
316 return cmd (iomUnitIdx, chan);
317 }
318