blob: 408ecff40132ff09a437439bb5d30b607fc6977f [file] [log] [blame] [raw]
Bob Supnik9af6fd22001-11-06 20:44:00 -08001/* pdp11_rx.c: RX11/RX01 floppy disk simulator
2
Mark Pizzolato4e5f9102013-09-04 19:50:47 -07003 Copyright (c) 1993-2013, Robert M Supnik
Bob Supnik9af6fd22001-11-06 20:44:00 -08004
5 Permission is hereby granted, free of charge, to any person obtaining a
6 copy of this software and associated documentation files (the "Software"),
7 to deal in the Software without restriction, including without limitation
8 the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 and/or sell copies of the Software, and to permit persons to whom the
10 Software is furnished to do so, subject to the following conditions:
11
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
14
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
Bob Supnikb7c1eae2005-09-09 18:09:00 -070022 Except as contained in this notice, the name of Robert M Supnik shall not be
23 used in advertising or otherwise to promote the sale, use or other dealings
Bob Supnik9af6fd22001-11-06 20:44:00 -080024 in this Software without prior written authorization from Robert M Supnik.
25
Bob Supnikb7c1eae2005-09-09 18:09:00 -070026 rx RX11/RX01 floppy disk
Bob Supnik9af6fd22001-11-06 20:44:00 -080027
Mark Pizzolatof0d41f12013-10-27 05:30:13 -070028 23-Oct-13 RMS Revised for new boot setup routine
Mark Pizzolato4e5f9102013-09-04 19:50:47 -070029 03-Sep-13 RMS Added explicit void * cast
Bob Supnikb7c1eae2005-09-09 18:09:00 -070030 07-Jul-05 RMS Removed extraneous externs
31 12-Oct-02 RMS Added autoconfigure support
32 08-Oct-02 RMS Added variable address support to bootstrap
33 Added vector change/display support
34 Revised state machine based on RX211
35 New data structures
36 Fixed reset of disabled device
37 26-Jan-02 RMS Revised bootstrap to conform to M9312
38 06-Jan-02 RMS Revised enable/disable support
39 30-Nov-01 RMS Added read only unit, extended SET/SHOW support
40 24-Nov-01 RMS Converted FLG to array
41 07-Sep-01 RMS Revised device disable and interrupt mechanisms
42 17-Jul-01 RMS Fixed warning from VC++ 6.0
43 26-Apr-01 RMS Added device enable/disable support
44 13-Apr-01 RMS Revised for register arrays
45 15-Feb-01 RMS Corrected bootstrap string
46 14-Apr-99 RMS Changed t_addr to unsigned
Bob Supnik9af6fd22001-11-06 20:44:00 -080047
48 An RX01 diskette consists of 77 tracks, each with 26 sectors of 128B.
49 Tracks are numbered 0-76, sectors 1-26.
50*/
51
52#include "pdp11_defs.h"
53
Bob Supnikb7c1eae2005-09-09 18:09:00 -070054#define RX_NUMTR 77 /* tracks/disk */
55#define RX_M_TRACK 0377
56#define RX_NUMSC 26 /* sectors/track */
57#define RX_M_SECTOR 0177
58#define RX_NUMBY 128 /* bytes/sector */
59#define RX_SIZE (RX_NUMTR * RX_NUMSC * RX_NUMBY) /* bytes/disk */
60#define RX_NUMDR 2 /* drives/controller */
61#define RX_M_NUMDR 01
62#define UNIT_V_WLK (UNIT_V_UF) /* write locked */
63#define UNIT_WLK (1u << UNIT_V_UF)
64#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */
Bob Supnik9af6fd22001-11-06 20:44:00 -080065
Bob Supnikb7c1eae2005-09-09 18:09:00 -070066#define IDLE 0 /* idle state */
67#define RWDS 1 /* rw, sect next */
68#define RWDT 2 /* rw, track next */
69#define RWXFR 3 /* rw, transfer */
70#define FILL 4 /* fill buffer */
71#define EMPTY 5 /* empty buffer */
72#define CMD_COMPLETE 6 /* set done next */
73#define INIT_COMPLETE 7 /* init compl next */
Bob Supnik9af6fd22001-11-06 20:44:00 -080074
Bob Supnikb7c1eae2005-09-09 18:09:00 -070075#define RXCS_V_FUNC 1 /* function */
76#define RXCS_M_FUNC 7
77#define RXCS_FILL 0 /* fill buffer */
78#define RXCS_EMPTY 1 /* empty buffer */
79#define RXCS_WRITE 2 /* write sector */
80#define RXCS_READ 3 /* read sector */
81#define RXCS_RXES 5 /* read status */
82#define RXCS_WRDEL 6 /* write del data */
83#define RXCS_ECODE 7 /* read error code */
84#define RXCS_V_DRV 4 /* drive select */
85#define RXCS_V_DONE 5 /* done */
86#define RXCS_V_IE 6 /* intr enable */
87#define RXCS_V_TR 7 /* xfer request */
88#define RXCS_V_INIT 14 /* init */
89#define RXCS_V_ERR 15 /* error */
90#define RXCS_FUNC (RXCS_M_FUNC << RXCS_V_FUNC)
91#define RXCS_DRV (1u << RXCS_V_DRV)
92#define RXCS_DONE (1u << RXCS_V_DONE)
93#define RXCS_IE (1u << RXCS_V_IE)
94#define RXCS_TR (1u << RXCS_V_TR)
95#define RXCS_INIT (1u << RXCS_V_INIT)
96#define RXCS_ERR (1u << RXCS_V_ERR)
97#define RXCS_ROUT (RXCS_ERR+RXCS_TR+RXCS_IE+RXCS_DONE)
98#define RXCS_IMP (RXCS_ROUT+RXCS_DRV+RXCS_FUNC)
99#define RXCS_RW (RXCS_IE) /* read/write */
100#define RXCS_GETFNC(x) (((x) >> RXCS_V_FUNC) & RXCS_M_FUNC)
Bob Supnik9af6fd22001-11-06 20:44:00 -0800101
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700102#define RXES_CRC 0001 /* CRC error */
103#define RXES_PAR 0002 /* parity error */
104#define RXES_ID 0004 /* init done */
105#define RXES_WLK 0010 /* write protect */
106#define RXES_DD 0100 /* deleted data */
107#define RXES_DRDY 0200 /* drive ready */
Bob Supnik9af6fd22001-11-06 20:44:00 -0800108
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700109#define TRACK u3 /* current track */
Bob Supnik9af6fd22001-11-06 20:44:00 -0800110#define CALC_DA(t,s) (((t) * RX_NUMSC) + ((s) - 1)) * RX_NUMBY
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800111
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700112extern int32 int_req[IPL_HLVL];
113
114int32 rx_csr = 0; /* control/status */
115int32 rx_dbr = 0; /* data buffer */
116int32 rx_esr = 0; /* error status */
117int32 rx_ecode = 0; /* error code */
118int32 rx_track = 0; /* desired track */
119int32 rx_sector = 0; /* desired sector */
120int32 rx_state = IDLE; /* controller state */
121int32 rx_stopioe = 1; /* stop on error */
122int32 rx_cwait = 100; /* command time */
123int32 rx_swait = 10; /* seek, per track */
124int32 rx_xwait = 1; /* tr set time */
125uint8 rx_buf[RX_NUMBY] = { 0 }; /* sector buffer */
126int32 rx_bptr = 0; /* buffer pointer */
127int32 rx_enb = 1; /* device enable */
Bob Supnikdf647512002-07-14 15:20:00 -0700128
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800129DEVICE rx_dev;
Bob Supnikdf647512002-07-14 15:20:00 -0700130t_stat rx_rd (int32 *data, int32 PA, int32 access);
131t_stat rx_wr (int32 data, int32 PA, int32 access);
Bob Supnik9af6fd22001-11-06 20:44:00 -0800132t_stat rx_svc (UNIT *uptr);
133t_stat rx_reset (DEVICE *dptr);
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800134t_stat rx_boot (int32 unitno, DEVICE *dptr);
Mark Pizzolatocf280ad2012-03-20 18:55:45 -0700135void rx_done (int32 esr_flags, int32 new_ecode);
Bob Supnik9af6fd22001-11-06 20:44:00 -0800136
137/* RX11 data structures
138
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700139 rx_dev RX device descriptor
140 rx_unit RX unit list
141 rx_reg RX register list
142 rx_mod RX modifier list
Bob Supnik9af6fd22001-11-06 20:44:00 -0800143*/
Bob Supnikdf647512002-07-14 15:20:00 -0700144
Mark Pizzolato7bed0912012-12-20 13:58:11 -0800145#define IOLN_RX 004
146
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700147DIB rx_dib = {
Mark Pizzolato7bed0912012-12-20 13:58:11 -0800148 IOBA_AUTO, IOLN_RX, &rx_rd, &rx_wr,
Timothe Litt91c7d262013-07-11 15:39:15 -0400149 1, IVCL (RX), VEC_AUTO, { NULL }, IOLN_RX,
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700150 };
Bob Supnik9af6fd22001-11-06 20:44:00 -0800151
152UNIT rx_unit[] = {
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700153 { UDATA (&rx_svc,
154 UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF, RX_SIZE) },
155 { UDATA (&rx_svc,
156 UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF, RX_SIZE) }
157 };
Bob Supnik9af6fd22001-11-06 20:44:00 -0800158
159REG rx_reg[] = {
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700160 { ORDATA (RXCS, rx_csr, 16) },
161 { ORDATA (RXDB, rx_dbr, 8) },
162 { ORDATA (RXES, rx_esr, 8) },
163 { ORDATA (RXERR, rx_ecode, 8) },
164 { ORDATA (RXTA, rx_track, 8) },
165 { ORDATA (RXSA, rx_sector, 8) },
166 { DRDATA (STAPTR, rx_state, 3), REG_RO },
167 { DRDATA (BUFPTR, rx_bptr, 7) },
168 { FLDATA (INT, IREQ (RX), INT_V_RX) },
169 { FLDATA (ERR, rx_csr, RXCS_V_ERR) },
170 { FLDATA (TR, rx_csr, RXCS_V_TR) },
171 { FLDATA (IE, rx_csr, RXCS_V_IE) },
172 { FLDATA (DONE, rx_csr, RXCS_V_DONE) },
173 { DRDATA (CTIME, rx_cwait, 24), PV_LEFT },
174 { DRDATA (STIME, rx_swait, 24), PV_LEFT },
175 { DRDATA (XTIME, rx_xwait, 24), PV_LEFT },
176 { FLDATA (STOP_IOE, rx_stopioe, 0) },
177 { BRDATA (SBUF, rx_buf, 8, 8, RX_NUMBY) },
178 { ORDATA (DEVADDR, rx_dib.ba, 32), REG_HRO },
179 { ORDATA (DEVVEC, rx_dib.vec, 16), REG_HRO },
180 { NULL }
181 };
Bob Supnik9af6fd22001-11-06 20:44:00 -0800182
183MTAB rx_mod[] = {
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700184 { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL },
185 { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL },
Mark Pizzolatofffad7c2012-03-19 16:05:24 -0700186#if defined (VM_PDP11)
Mark Pizzolato55693fb2013-02-02 17:27:22 -0800187 { MTAB_XTD|MTAB_VDV|MTAB_VALR, 004, "ADDRESS", "ADDRESS",
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700188 &set_addr, &show_addr, NULL },
Mark Pizzolato55693fb2013-02-02 17:27:22 -0800189 { MTAB_XTD|MTAB_VDV, 0, NULL, "AUTOCONFIGURE",
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700190 &set_addr_flt, NULL, NULL },
Mark Pizzolato55693fb2013-02-02 17:27:22 -0800191 { MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "VECTOR", "VECTOR",
Mark Pizzolatofffad7c2012-03-19 16:05:24 -0700192 &set_vec, &show_vec, NULL },
193#else
194 { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS",
195 NULL, &show_addr, NULL },
196 { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR",
197 NULL, &show_vec, NULL },
198#endif
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700199 { 0 }
200 };
Bob Supnik9af6fd22001-11-06 20:44:00 -0800201
202DEVICE rx_dev = {
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700203 "RX", rx_unit, rx_reg, rx_mod,
204 RX_NUMDR, 8, 20, 1, 8, 8,
205 NULL, NULL, &rx_reset,
206 &rx_boot, NULL, NULL,
Mark Pizzolato7bed0912012-12-20 13:58:11 -0800207 &rx_dib, DEV_DISABLE | DEV_UBUS | DEV_QBUS
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700208 };
209
Bob Supnik9af6fd22001-11-06 20:44:00 -0800210/* I/O dispatch routine, I/O addresses 17777170 - 17777172
211
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700212 17777170 floppy CSR
213 17777172 floppy data register
Bob Supnik9af6fd22001-11-06 20:44:00 -0800214*/
215
216t_stat rx_rd (int32 *data, int32 PA, int32 access)
217{
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700218switch ((PA >> 1) & 1) { /* decode PA<1> */
219
220 case 0: /* RXCS */
221 rx_csr = rx_csr & RXCS_IMP; /* clear junk */
222 *data = rx_csr & RXCS_ROUT;
223 break;
224
225 case 1: /* RXDB */
226 if ((rx_state == EMPTY) && (rx_csr & RXCS_TR)) {/* empty? */
227 sim_activate (&rx_unit[0], rx_xwait);
228 rx_csr = rx_csr & ~RXCS_TR; /* clear xfer */
229 }
230 *data = rx_dbr; /* return data */
231 break;
232 } /* end switch PA */
233
Bob Supnik89bcd022001-11-06 20:58:00 -0800234return SCPE_OK;
Bob Supnik9af6fd22001-11-06 20:44:00 -0800235}
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700236
Bob Supnik9af6fd22001-11-06 20:44:00 -0800237t_stat rx_wr (int32 data, int32 PA, int32 access)
238{
239int32 drv;
240
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700241switch ((PA >> 1) & 1) { /* decode PA<1> */
Bob Supnik9af6fd22001-11-06 20:44:00 -0800242
243/* Writing RXCS, three cases:
244 1. Writing INIT, reset device
245 2. Idle and writing new function
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700246 - clear error, done, transfer ready, int req
247 - save int enable, function, drive
248 - start new function
Bob Supnik9af6fd22001-11-06 20:44:00 -0800249 3. Otherwise, write IE and update interrupts
250*/
251
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700252 case 0: /* RXCS */
253 rx_csr = rx_csr & RXCS_IMP; /* clear junk */
254 if (access == WRITEB) data = (PA & 1)? /* write byte? */
255 (rx_csr & 0377) | (data << 8): (rx_csr & ~0377) | data;
256 if (data & RXCS_INIT) { /* initialize? */
257 rx_reset (&rx_dev); /* reset device */
258 return SCPE_OK; /* end if init */
259 }
260 if ((data & CSR_GO) && (rx_state == IDLE)) { /* new function? */
261 rx_csr = data & (RXCS_IE + RXCS_DRV + RXCS_FUNC);
262 drv = ((rx_csr & RXCS_DRV)? 1: 0); /* reselect drive */
263 rx_bptr = 0; /* clear buf pointer */
264 switch (RXCS_GETFNC (data)) { /* case on func */
265
266 case RXCS_FILL:
267 rx_state = FILL; /* state = fill */
268 rx_csr = rx_csr | RXCS_TR; /* xfer is ready */
269 break;
270
271 case RXCS_EMPTY:
272 rx_state = EMPTY; /* state = empty */
273 sim_activate (&rx_unit[drv], rx_xwait);
274 break;
275
276 case RXCS_READ: case RXCS_WRITE: case RXCS_WRDEL:
277 rx_state = RWDS; /* state = get sector */
278 rx_csr = rx_csr | RXCS_TR; /* xfer is ready */
279 rx_esr = rx_esr & RXES_ID; /* clear errors */
280 break;
281
282 default:
283 rx_state = CMD_COMPLETE; /* state = cmd compl */
284 sim_activate (&rx_unit[drv], rx_cwait);
285 break;
286 } /* end switch func */
287 return SCPE_OK;
288 } /* end if GO */
Bob Supnik9c4779c2009-02-08 09:06:00 -0800289 if ((data & RXCS_IE) == 0)
290 CLR_INT (RX);
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700291 else if ((rx_csr & (RXCS_DONE + RXCS_IE)) == RXCS_DONE)
292 SET_INT (RX);
293 rx_csr = (rx_csr & ~RXCS_RW) | (data & RXCS_RW);
294 break; /* end case RXCS */
295
Bob Supnik9af6fd22001-11-06 20:44:00 -0800296/* Accessing RXDB, two cases:
297 1. Write idle, write
298 2. Write not idle and TR set, state dependent
299*/
300
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700301 case 1: /* RXDB */
302 if ((PA & 1) || ((rx_state != IDLE) && ((rx_csr & RXCS_TR) == 0)))
303 return SCPE_OK; /* if ~IDLE, need tr */
304 rx_dbr = data & 0377; /* save data */
305 if ((rx_state != IDLE) && (rx_state != EMPTY)) {
306 drv = ((rx_csr & RXCS_DRV)? 1: 0); /* select drive */
307 sim_activate (&rx_unit[drv], rx_xwait); /* sched event */
308 rx_csr = rx_csr & ~RXCS_TR; /* clear xfer */
309 }
310 break; /* end case RXDB */
311 } /* end switch PA */
312
Bob Supnik89bcd022001-11-06 20:58:00 -0800313return SCPE_OK;
Bob Supnik9af6fd22001-11-06 20:44:00 -0800314}
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700315
Bob Supnik9af6fd22001-11-06 20:44:00 -0800316/* Unit service; the action to be taken depends on the transfer state:
317
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700318 IDLE Should never get here
319 RWDS Save sector, set TR, set RWDT
320 RWDT Save track, set RWXFR
321 RWXFR Read/write buffer
322 FILL copy ir to rx_buf[rx_bptr], advance ptr
323 if rx_bptr > max, finish command, else set tr
324 EMPTY if rx_bptr > max, finish command, else
325 copy rx_buf[rx_bptr] to ir, advance ptr, set tr
326 CMD_COMPLETE copy requested data to ir, finish command
Bob Supnik9af6fd22001-11-06 20:44:00 -0800327 INIT_COMPLETE read drive 0, track 1, sector 1 to buffer, finish command
328
329 For RWDT and CMD_COMPLETE, the input argument is the selected drive;
330 otherwise, it is drive 0.
331*/
332
333t_stat rx_svc (UNIT *uptr)
334{
335int32 i, func;
Bob Supnik4ffd3be2003-06-25 09:20:00 -0700336uint32 da;
Mark Pizzolato4e5f9102013-09-04 19:50:47 -0700337int8 *fbuf = (int8 *) uptr->filebuf;
Bob Supnik9af6fd22001-11-06 20:44:00 -0800338
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700339func = RXCS_GETFNC (rx_csr); /* get function */
340switch (rx_state) { /* case on state */
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800341
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700342 case IDLE: /* idle */
343 return SCPE_IERR; /* done */
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800344
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700345 case EMPTY: /* empty buffer */
Bob Supnik9c4779c2009-02-08 09:06:00 -0800346 if (rx_bptr >= RX_NUMBY) /* done all? */
347 rx_done (0, 0);
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700348 else {
349 rx_dbr = rx_buf[rx_bptr]; /* get next */
350 rx_bptr = rx_bptr + 1;
351 rx_csr = rx_csr | RXCS_TR; /* set xfer */
352 }
353 break;
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800354
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700355 case FILL: /* fill buffer */
Mark Pizzolato02cb5c22014-02-14 17:07:45 -0800356 rx_buf[rx_bptr] = (uint8)rx_dbr; /* write next */
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700357 rx_bptr = rx_bptr + 1;
Bob Supnik9c4779c2009-02-08 09:06:00 -0800358 if (rx_bptr < RX_NUMBY) /* more? set xfer */
359 rx_csr = rx_csr | RXCS_TR;
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700360 else rx_done (0, 0); /* else done */
361 break;
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800362
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700363 case RWDS: /* wait for sector */
364 rx_sector = rx_dbr & RX_M_SECTOR; /* save sector */
365 rx_csr = rx_csr | RXCS_TR; /* set xfer */
366 rx_state = RWDT; /* advance state */
367 return SCPE_OK;
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800368
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700369 case RWDT: /* wait for track */
370 rx_track = rx_dbr & RX_M_TRACK; /* save track */
371 rx_state = RWXFR;
372 sim_activate (uptr, /* sched done */
373 rx_swait * abs (rx_track - uptr->TRACK));
374 return SCPE_OK;
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800375
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700376 case RWXFR:
377 if ((uptr->flags & UNIT_BUF) == 0) { /* not buffered? */
378 rx_done (0, 0110); /* done, error */
379 return IORETURN (rx_stopioe, SCPE_UNATT);
380 }
381 if (rx_track >= RX_NUMTR) { /* bad track? */
382 rx_done (0, 0040); /* done, error */
383 break;
384 }
385 uptr->TRACK = rx_track; /* now on track */
Bob Supnik53d02f72007-02-03 14:59:00 -0800386 if ((rx_sector == 0) || (rx_sector > RX_NUMSC)) { /* bad sect? */
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700387 rx_done (0, 0070); /* done, error */
388 break;
389 }
390 da = CALC_DA (rx_track, rx_sector); /* get disk address */
Bob Supnik9c4779c2009-02-08 09:06:00 -0800391 if (func == RXCS_WRDEL) /* del data? */
392 rx_esr = rx_esr | RXES_DD;
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700393 if (func == RXCS_READ) { /* read? */
394 for (i = 0; i < RX_NUMBY; i++)
395 rx_buf[i] = fbuf[da + i];
396 }
397 else {
398 if (uptr->flags & UNIT_WPRT) { /* write and locked? */
399 rx_done (RXES_WLK, 0100); /* done, error */
400 break;
401 }
402 for (i = 0; i < RX_NUMBY; i++) /* write */
403 fbuf[da + i] = rx_buf[i];
404 da = da + RX_NUMBY;
Bob Supnik9c4779c2009-02-08 09:06:00 -0800405 if (da > uptr->hwmark)
406 uptr->hwmark = da;
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700407 }
408 rx_done (0, 0); /* done */
409 break;
410
411 case CMD_COMPLETE: /* command complete */
412 if (func == RXCS_ECODE) { /* read ecode? */
413 rx_dbr = rx_ecode; /* set dbr */
414 rx_done (0, -1); /* don't update */
415 }
416 else rx_done (0, 0);
417 break;
418
419 case INIT_COMPLETE: /* init complete */
420 rx_unit[0].TRACK = 1; /* drive 0 to trk 1 */
421 rx_unit[1].TRACK = 0; /* drive 1 to trk 0 */
422 if ((rx_unit[0].flags & UNIT_BUF) == 0) { /* not buffered? */
423 rx_done (RXES_ID, 0010); /* init done, error */
424 break;
425 }
426 da = CALC_DA (1, 1); /* track 1, sector 1 */
427 for (i = 0; i < RX_NUMBY; i++) /* read sector */
428 rx_buf[i] = fbuf[da + i];
429 rx_done (RXES_ID, 0); /* set done */
Bob Supnik9c4779c2009-02-08 09:06:00 -0800430 if ((rx_unit[1].flags & UNIT_ATT) == 0)
431 rx_ecode = 0020;
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700432 break;
433 } /* end case state */
434
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800435return SCPE_OK;
Bob Supnik9af6fd22001-11-06 20:44:00 -0800436}
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700437
Bob Supnik9af6fd22001-11-06 20:44:00 -0800438/* Command complete. Set done and put final value in interface register,
439 request interrupt if needed, return to IDLE state.
440*/
441
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800442void rx_done (int32 esr_flags, int32 new_ecode)
Bob Supnik9af6fd22001-11-06 20:44:00 -0800443{
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800444int32 drv = (rx_csr & RXCS_DRV)? 1: 0;
445
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700446rx_state = IDLE; /* now idle */
447rx_csr = rx_csr | RXCS_DONE; /* set done */
448if (rx_csr & RXCS_IE) SET_INT (RX); /* if ie, intr */
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800449rx_esr = (rx_esr | esr_flags) & ~RXES_DRDY;
450if (rx_unit[drv].flags & UNIT_ATT)
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700451 rx_esr = rx_esr | RXES_DRDY;
Bob Supnik9c4779c2009-02-08 09:06:00 -0800452if (new_ecode > 0) /* test for error */
453 rx_csr = rx_csr | RXCS_ERR;
454if (new_ecode < 0) /* don't update? */
455 return;
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700456rx_ecode = new_ecode; /* update ecode */
457rx_dbr = rx_esr; /* update RXDB */
Bob Supnik9af6fd22001-11-06 20:44:00 -0800458return;
459}
460
461/* Device initialization. The RX is one of the few devices that schedules
462 an I/O transfer as part of its initialization.
463*/
464
465t_stat rx_reset (DEVICE *dptr)
466{
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700467rx_csr = rx_dbr = 0; /* clear regs */
468rx_esr = rx_ecode = 0; /* clear error */
469rx_track = rx_sector = 0; /* clear addr */
470rx_state = IDLE; /* ctrl idle */
471CLR_INT (RX); /* clear int req */
472sim_cancel (&rx_unit[1]); /* cancel drive 1 */
Bob Supnik9c4779c2009-02-08 09:06:00 -0800473if (dptr->flags & DEV_DIS) /* disabled? */
474 sim_cancel (&rx_unit[0]);
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700475else if (rx_unit[0].flags & UNIT_BUF) { /* attached? */
476 rx_state = INIT_COMPLETE; /* yes, sched init */
477 sim_activate (&rx_unit[0], rx_swait * abs (1 - rx_unit[0].TRACK));
478 }
479else rx_done (0, 0010); /* no, error */
480return auto_config (0, 0); /* run autoconfig */
Bob Supnik9af6fd22001-11-06 20:44:00 -0800481}
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700482
Bob Supnik9af6fd22001-11-06 20:44:00 -0800483/* Device bootstrap */
484
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700485#define BOOT_START 02000 /* start */
486#define BOOT_ENTRY (BOOT_START + 002) /* entry */
487#define BOOT_UNIT (BOOT_START + 010) /* unit number */
488#define BOOT_CSR (BOOT_START + 026) /* CSR */
489#define BOOT_LEN (sizeof (boot_rom) / sizeof (int16))
Bob Supnik9af6fd22001-11-06 20:44:00 -0800490
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800491static const uint16 boot_rom[] = {
Bob Supnikb7c1eae2005-09-09 18:09:00 -0700492 042130, /* "XD" */
493 0012706, BOOT_START, /* MOV #boot_start, SP */
494 0012700, 0000000, /* MOV #unit, R0 ; unit number */
495 0010003, /* MOV R0, R3 */
496 0006303, /* ASL R3 */
497 0006303, /* ASL R3 */
498 0006303, /* ASL R3 */
499 0006303, /* ASL R3 */
500 0012701, 0177170, /* MOV #RXCS, R1 ; csr */
501 0032711, 0000040, /* BITB #40, (R1) ; ready? */
502 0001775, /* BEQ .-4 */
503 0052703, 0000007, /* BIS #READ+GO, R3 */
504 0010311, /* MOV R3, (R1) ; read & go */
505 0105711, /* TSTB (R1) ; xfr ready? */
506 0100376, /* BPL .-2 */
507 0012761, 0000001, 0000002, /* MOV #1, 2(R1) ; sector */
508 0105711, /* TSTB (R1) ; xfr ready? */
509 0100376, /* BPL .-2 */
510 0012761, 0000001, 0000002, /* MOV #1, 2(R1) ; track */
511 0005003, /* CLR R3 */
512 0032711, 0000040, /* BITB #40, (R1) ; ready? */
513 0001775, /* BEQ .-4 */
514 0012711, 0000003, /* MOV #EMPTY+GO, (R1) ; empty & go */
515 0105711, /* TSTB (R1) ; xfr, done? */
516 0001776, /* BEQ .-2 */
517 0100003, /* BPL .+010 */
518 0116123, 0000002, /* MOVB 2(R1), (R3)+ ; move byte */
519 0000772, /* BR .-012 */
520 0005002, /* CLR R2 */
521 0005003, /* CLR R3 */
522 0012704, BOOT_START+020, /* MOV #START+20, R4 */
523 0005005, /* CLR R5 */
524 0005007 /* CLR R7 */
525 };
Bob Supnik9af6fd22001-11-06 20:44:00 -0800526
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800527t_stat rx_boot (int32 unitno, DEVICE *dptr)
Bob Supnik9af6fd22001-11-06 20:44:00 -0800528{
Mark Pizzolato50cf91d2012-12-18 09:52:14 -0800529size_t i;
Bob Supnik4d6dfa42001-11-06 20:50:00 -0800530extern uint16 *M;
Bob Supnik9af6fd22001-11-06 20:44:00 -0800531
Bob Supnik9c4779c2009-02-08 09:06:00 -0800532for (i = 0; i < BOOT_LEN; i++)
533 M[(BOOT_START >> 1) + i] = boot_rom[i];
Bob Supnik9af6fd22001-11-06 20:44:00 -0800534M[BOOT_UNIT >> 1] = unitno & RX_M_NUMDR;
Bob Supnik2c2dd5e2002-11-17 15:54:00 -0800535M[BOOT_CSR >> 1] = rx_dib.ba & DMASK;
Mark Pizzolatof0d41f12013-10-27 05:30:13 -0700536cpu_set_boot (BOOT_ENTRY);
Bob Supnik9af6fd22001-11-06 20:44:00 -0800537return SCPE_OK;
538}