Bob Supnik | 9af6fd2 | 2001-11-06 20:44:00 -0800 | [diff] [blame] | 1 | /* pdp11_rx.c: RX11/RX01 floppy disk simulator
|
| 2 |
|
Mark Pizzolato | 4e5f910 | 2013-09-04 19:50:47 -0700 | [diff] [blame] | 3 | Copyright (c) 1993-2013, Robert M Supnik
|
Bob Supnik | 9af6fd2 | 2001-11-06 20:44:00 -0800 | [diff] [blame] | 4 |
|
| 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 Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 22 | 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 Supnik | 9af6fd2 | 2001-11-06 20:44:00 -0800 | [diff] [blame] | 24 | in this Software without prior written authorization from Robert M Supnik.
|
| 25 |
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 26 | rx RX11/RX01 floppy disk
|
Bob Supnik | 9af6fd2 | 2001-11-06 20:44:00 -0800 | [diff] [blame] | 27 |
|
Mark Pizzolato | f0d41f1 | 2013-10-27 05:30:13 -0700 | [diff] [blame] | 28 | 23-Oct-13 RMS Revised for new boot setup routine
|
Mark Pizzolato | 4e5f910 | 2013-09-04 19:50:47 -0700 | [diff] [blame] | 29 | 03-Sep-13 RMS Added explicit void * cast
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 30 | 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 Supnik | 9af6fd2 | 2001-11-06 20:44:00 -0800 | [diff] [blame] | 47 |
|
| 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 Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 54 | #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 Supnik | 9af6fd2 | 2001-11-06 20:44:00 -0800 | [diff] [blame] | 65 |
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 66 | #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 Supnik | 9af6fd2 | 2001-11-06 20:44:00 -0800 | [diff] [blame] | 74 |
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 75 | #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 Supnik | 9af6fd2 | 2001-11-06 20:44:00 -0800 | [diff] [blame] | 101 |
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 102 | #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 Supnik | 9af6fd2 | 2001-11-06 20:44:00 -0800 | [diff] [blame] | 108 |
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 109 | #define TRACK u3 /* current track */
|
Bob Supnik | 9af6fd2 | 2001-11-06 20:44:00 -0800 | [diff] [blame] | 110 | #define CALC_DA(t,s) (((t) * RX_NUMSC) + ((s) - 1)) * RX_NUMBY
|
Bob Supnik | 2c2dd5e | 2002-11-17 15:54:00 -0800 | [diff] [blame] | 111 |
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 112 | extern int32 int_req[IPL_HLVL];
|
| 113 |
|
| 114 | int32 rx_csr = 0; /* control/status */
|
| 115 | int32 rx_dbr = 0; /* data buffer */
|
| 116 | int32 rx_esr = 0; /* error status */
|
| 117 | int32 rx_ecode = 0; /* error code */
|
| 118 | int32 rx_track = 0; /* desired track */
|
| 119 | int32 rx_sector = 0; /* desired sector */
|
| 120 | int32 rx_state = IDLE; /* controller state */
|
| 121 | int32 rx_stopioe = 1; /* stop on error */
|
| 122 | int32 rx_cwait = 100; /* command time */
|
| 123 | int32 rx_swait = 10; /* seek, per track */
|
| 124 | int32 rx_xwait = 1; /* tr set time */
|
| 125 | uint8 rx_buf[RX_NUMBY] = { 0 }; /* sector buffer */
|
| 126 | int32 rx_bptr = 0; /* buffer pointer */
|
| 127 | int32 rx_enb = 1; /* device enable */
|
Bob Supnik | df64751 | 2002-07-14 15:20:00 -0700 | [diff] [blame] | 128 |
|
Bob Supnik | 2c2dd5e | 2002-11-17 15:54:00 -0800 | [diff] [blame] | 129 | DEVICE rx_dev;
|
Bob Supnik | df64751 | 2002-07-14 15:20:00 -0700 | [diff] [blame] | 130 | t_stat rx_rd (int32 *data, int32 PA, int32 access);
|
| 131 | t_stat rx_wr (int32 data, int32 PA, int32 access);
|
Bob Supnik | 9af6fd2 | 2001-11-06 20:44:00 -0800 | [diff] [blame] | 132 | t_stat rx_svc (UNIT *uptr);
|
| 133 | t_stat rx_reset (DEVICE *dptr);
|
Bob Supnik | 2c2dd5e | 2002-11-17 15:54:00 -0800 | [diff] [blame] | 134 | t_stat rx_boot (int32 unitno, DEVICE *dptr);
|
Mark Pizzolato | cf280ad | 2012-03-20 18:55:45 -0700 | [diff] [blame] | 135 | void rx_done (int32 esr_flags, int32 new_ecode);
|
Bob Supnik | 9af6fd2 | 2001-11-06 20:44:00 -0800 | [diff] [blame] | 136 |
|
| 137 | /* RX11 data structures
|
| 138 |
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 139 | rx_dev RX device descriptor
|
| 140 | rx_unit RX unit list
|
| 141 | rx_reg RX register list
|
| 142 | rx_mod RX modifier list
|
Bob Supnik | 9af6fd2 | 2001-11-06 20:44:00 -0800 | [diff] [blame] | 143 | */
|
Bob Supnik | df64751 | 2002-07-14 15:20:00 -0700 | [diff] [blame] | 144 |
|
Mark Pizzolato | 7bed091 | 2012-12-20 13:58:11 -0800 | [diff] [blame] | 145 | #define IOLN_RX 004
|
| 146 |
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 147 | DIB rx_dib = {
|
Mark Pizzolato | 7bed091 | 2012-12-20 13:58:11 -0800 | [diff] [blame] | 148 | IOBA_AUTO, IOLN_RX, &rx_rd, &rx_wr,
|
Timothe Litt | 91c7d26 | 2013-07-11 15:39:15 -0400 | [diff] [blame] | 149 | 1, IVCL (RX), VEC_AUTO, { NULL }, IOLN_RX,
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 150 | };
|
Bob Supnik | 9af6fd2 | 2001-11-06 20:44:00 -0800 | [diff] [blame] | 151 |
|
| 152 | UNIT rx_unit[] = {
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 153 | { 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 Supnik | 9af6fd2 | 2001-11-06 20:44:00 -0800 | [diff] [blame] | 158 |
|
| 159 | REG rx_reg[] = {
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 160 | { 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 Supnik | 9af6fd2 | 2001-11-06 20:44:00 -0800 | [diff] [blame] | 182 |
|
| 183 | MTAB rx_mod[] = {
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 184 | { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL },
|
| 185 | { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL },
|
Mark Pizzolato | fffad7c | 2012-03-19 16:05:24 -0700 | [diff] [blame] | 186 | #if defined (VM_PDP11)
|
Mark Pizzolato | 55693fb | 2013-02-02 17:27:22 -0800 | [diff] [blame] | 187 | { MTAB_XTD|MTAB_VDV|MTAB_VALR, 004, "ADDRESS", "ADDRESS",
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 188 | &set_addr, &show_addr, NULL },
|
Mark Pizzolato | 55693fb | 2013-02-02 17:27:22 -0800 | [diff] [blame] | 189 | { MTAB_XTD|MTAB_VDV, 0, NULL, "AUTOCONFIGURE",
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 190 | &set_addr_flt, NULL, NULL },
|
Mark Pizzolato | 55693fb | 2013-02-02 17:27:22 -0800 | [diff] [blame] | 191 | { MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "VECTOR", "VECTOR",
|
Mark Pizzolato | fffad7c | 2012-03-19 16:05:24 -0700 | [diff] [blame] | 192 | &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 Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 199 | { 0 }
|
| 200 | };
|
Bob Supnik | 9af6fd2 | 2001-11-06 20:44:00 -0800 | [diff] [blame] | 201 |
|
| 202 | DEVICE rx_dev = {
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 203 | "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 Pizzolato | 7bed091 | 2012-12-20 13:58:11 -0800 | [diff] [blame] | 207 | &rx_dib, DEV_DISABLE | DEV_UBUS | DEV_QBUS
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 208 | };
|
| 209 |
|
Bob Supnik | 9af6fd2 | 2001-11-06 20:44:00 -0800 | [diff] [blame] | 210 | /* I/O dispatch routine, I/O addresses 17777170 - 17777172
|
| 211 |
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 212 | 17777170 floppy CSR
|
| 213 | 17777172 floppy data register
|
Bob Supnik | 9af6fd2 | 2001-11-06 20:44:00 -0800 | [diff] [blame] | 214 | */
|
| 215 |
|
| 216 | t_stat rx_rd (int32 *data, int32 PA, int32 access)
|
| 217 | {
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 218 | switch ((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 Supnik | 89bcd02 | 2001-11-06 20:58:00 -0800 | [diff] [blame] | 234 | return SCPE_OK;
|
Bob Supnik | 9af6fd2 | 2001-11-06 20:44:00 -0800 | [diff] [blame] | 235 | }
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 236 |
|
Bob Supnik | 9af6fd2 | 2001-11-06 20:44:00 -0800 | [diff] [blame] | 237 | t_stat rx_wr (int32 data, int32 PA, int32 access)
|
| 238 | {
|
| 239 | int32 drv;
|
| 240 |
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 241 | switch ((PA >> 1) & 1) { /* decode PA<1> */
|
Bob Supnik | 9af6fd2 | 2001-11-06 20:44:00 -0800 | [diff] [blame] | 242 |
|
| 243 | /* Writing RXCS, three cases:
|
| 244 | 1. Writing INIT, reset device
|
| 245 | 2. Idle and writing new function
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 246 | - clear error, done, transfer ready, int req
|
| 247 | - save int enable, function, drive
|
| 248 | - start new function
|
Bob Supnik | 9af6fd2 | 2001-11-06 20:44:00 -0800 | [diff] [blame] | 249 | 3. Otherwise, write IE and update interrupts
|
| 250 | */
|
| 251 |
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 252 | 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 Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 289 | if ((data & RXCS_IE) == 0)
|
| 290 | CLR_INT (RX);
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 291 | 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 Supnik | 9af6fd2 | 2001-11-06 20:44:00 -0800 | [diff] [blame] | 296 | /* Accessing RXDB, two cases:
|
| 297 | 1. Write idle, write
|
| 298 | 2. Write not idle and TR set, state dependent
|
| 299 | */
|
| 300 |
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 301 | 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 Supnik | 89bcd02 | 2001-11-06 20:58:00 -0800 | [diff] [blame] | 313 | return SCPE_OK;
|
Bob Supnik | 9af6fd2 | 2001-11-06 20:44:00 -0800 | [diff] [blame] | 314 | }
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 315 |
|
Bob Supnik | 9af6fd2 | 2001-11-06 20:44:00 -0800 | [diff] [blame] | 316 | /* Unit service; the action to be taken depends on the transfer state:
|
| 317 |
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 318 | 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 Supnik | 9af6fd2 | 2001-11-06 20:44:00 -0800 | [diff] [blame] | 327 | 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 |
|
| 333 | t_stat rx_svc (UNIT *uptr)
|
| 334 | {
|
| 335 | int32 i, func;
|
Bob Supnik | 4ffd3be | 2003-06-25 09:20:00 -0700 | [diff] [blame] | 336 | uint32 da;
|
Mark Pizzolato | 4e5f910 | 2013-09-04 19:50:47 -0700 | [diff] [blame] | 337 | int8 *fbuf = (int8 *) uptr->filebuf;
|
Bob Supnik | 9af6fd2 | 2001-11-06 20:44:00 -0800 | [diff] [blame] | 338 |
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 339 | func = RXCS_GETFNC (rx_csr); /* get function */
|
| 340 | switch (rx_state) { /* case on state */
|
Bob Supnik | 2c2dd5e | 2002-11-17 15:54:00 -0800 | [diff] [blame] | 341 |
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 342 | case IDLE: /* idle */
|
| 343 | return SCPE_IERR; /* done */
|
Bob Supnik | 2c2dd5e | 2002-11-17 15:54:00 -0800 | [diff] [blame] | 344 |
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 345 | case EMPTY: /* empty buffer */
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 346 | if (rx_bptr >= RX_NUMBY) /* done all? */
|
| 347 | rx_done (0, 0);
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 348 | 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 Supnik | 2c2dd5e | 2002-11-17 15:54:00 -0800 | [diff] [blame] | 354 |
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 355 | case FILL: /* fill buffer */
|
Mark Pizzolato | 02cb5c2 | 2014-02-14 17:07:45 -0800 | [diff] [blame] | 356 | rx_buf[rx_bptr] = (uint8)rx_dbr; /* write next */
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 357 | rx_bptr = rx_bptr + 1;
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 358 | if (rx_bptr < RX_NUMBY) /* more? set xfer */
|
| 359 | rx_csr = rx_csr | RXCS_TR;
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 360 | else rx_done (0, 0); /* else done */
|
| 361 | break;
|
Bob Supnik | 2c2dd5e | 2002-11-17 15:54:00 -0800 | [diff] [blame] | 362 |
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 363 | 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 Supnik | 2c2dd5e | 2002-11-17 15:54:00 -0800 | [diff] [blame] | 368 |
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 369 | 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 Supnik | 2c2dd5e | 2002-11-17 15:54:00 -0800 | [diff] [blame] | 375 |
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 376 | 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 Supnik | 53d02f7 | 2007-02-03 14:59:00 -0800 | [diff] [blame] | 386 | if ((rx_sector == 0) || (rx_sector > RX_NUMSC)) { /* bad sect? */
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 387 | rx_done (0, 0070); /* done, error */
|
| 388 | break;
|
| 389 | }
|
| 390 | da = CALC_DA (rx_track, rx_sector); /* get disk address */
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 391 | if (func == RXCS_WRDEL) /* del data? */
|
| 392 | rx_esr = rx_esr | RXES_DD;
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 393 | 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 Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 405 | if (da > uptr->hwmark)
|
| 406 | uptr->hwmark = da;
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 407 | }
|
| 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 Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 430 | if ((rx_unit[1].flags & UNIT_ATT) == 0)
|
| 431 | rx_ecode = 0020;
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 432 | break;
|
| 433 | } /* end case state */
|
| 434 |
|
Bob Supnik | 2c2dd5e | 2002-11-17 15:54:00 -0800 | [diff] [blame] | 435 | return SCPE_OK;
|
Bob Supnik | 9af6fd2 | 2001-11-06 20:44:00 -0800 | [diff] [blame] | 436 | }
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 437 |
|
Bob Supnik | 9af6fd2 | 2001-11-06 20:44:00 -0800 | [diff] [blame] | 438 | /* Command complete. Set done and put final value in interface register,
|
| 439 | request interrupt if needed, return to IDLE state.
|
| 440 | */
|
| 441 |
|
Bob Supnik | 2c2dd5e | 2002-11-17 15:54:00 -0800 | [diff] [blame] | 442 | void rx_done (int32 esr_flags, int32 new_ecode)
|
Bob Supnik | 9af6fd2 | 2001-11-06 20:44:00 -0800 | [diff] [blame] | 443 | {
|
Bob Supnik | 2c2dd5e | 2002-11-17 15:54:00 -0800 | [diff] [blame] | 444 | int32 drv = (rx_csr & RXCS_DRV)? 1: 0;
|
| 445 |
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 446 | rx_state = IDLE; /* now idle */
|
| 447 | rx_csr = rx_csr | RXCS_DONE; /* set done */
|
| 448 | if (rx_csr & RXCS_IE) SET_INT (RX); /* if ie, intr */
|
Bob Supnik | 2c2dd5e | 2002-11-17 15:54:00 -0800 | [diff] [blame] | 449 | rx_esr = (rx_esr | esr_flags) & ~RXES_DRDY;
|
| 450 | if (rx_unit[drv].flags & UNIT_ATT)
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 451 | rx_esr = rx_esr | RXES_DRDY;
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 452 | if (new_ecode > 0) /* test for error */
|
| 453 | rx_csr = rx_csr | RXCS_ERR;
|
| 454 | if (new_ecode < 0) /* don't update? */
|
| 455 | return;
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 456 | rx_ecode = new_ecode; /* update ecode */
|
| 457 | rx_dbr = rx_esr; /* update RXDB */
|
Bob Supnik | 9af6fd2 | 2001-11-06 20:44:00 -0800 | [diff] [blame] | 458 | return;
|
| 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 |
|
| 465 | t_stat rx_reset (DEVICE *dptr)
|
| 466 | {
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 467 | rx_csr = rx_dbr = 0; /* clear regs */
|
| 468 | rx_esr = rx_ecode = 0; /* clear error */
|
| 469 | rx_track = rx_sector = 0; /* clear addr */
|
| 470 | rx_state = IDLE; /* ctrl idle */
|
| 471 | CLR_INT (RX); /* clear int req */
|
| 472 | sim_cancel (&rx_unit[1]); /* cancel drive 1 */
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 473 | if (dptr->flags & DEV_DIS) /* disabled? */
|
| 474 | sim_cancel (&rx_unit[0]);
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 475 | else 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 | }
|
| 479 | else rx_done (0, 0010); /* no, error */
|
| 480 | return auto_config (0, 0); /* run autoconfig */
|
Bob Supnik | 9af6fd2 | 2001-11-06 20:44:00 -0800 | [diff] [blame] | 481 | }
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 482 |
|
Bob Supnik | 9af6fd2 | 2001-11-06 20:44:00 -0800 | [diff] [blame] | 483 | /* Device bootstrap */
|
| 484 |
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 485 | #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 Supnik | 9af6fd2 | 2001-11-06 20:44:00 -0800 | [diff] [blame] | 490 |
|
Bob Supnik | 2c2dd5e | 2002-11-17 15:54:00 -0800 | [diff] [blame] | 491 | static const uint16 boot_rom[] = {
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 492 | 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 Supnik | 9af6fd2 | 2001-11-06 20:44:00 -0800 | [diff] [blame] | 526 |
|
Bob Supnik | 2c2dd5e | 2002-11-17 15:54:00 -0800 | [diff] [blame] | 527 | t_stat rx_boot (int32 unitno, DEVICE *dptr)
|
Bob Supnik | 9af6fd2 | 2001-11-06 20:44:00 -0800 | [diff] [blame] | 528 | {
|
Mark Pizzolato | 50cf91d | 2012-12-18 09:52:14 -0800 | [diff] [blame] | 529 | size_t i;
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 530 | extern uint16 *M;
|
Bob Supnik | 9af6fd2 | 2001-11-06 20:44:00 -0800 | [diff] [blame] | 531 |
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 532 | for (i = 0; i < BOOT_LEN; i++)
|
| 533 | M[(BOOT_START >> 1) + i] = boot_rom[i];
|
Bob Supnik | 9af6fd2 | 2001-11-06 20:44:00 -0800 | [diff] [blame] | 534 | M[BOOT_UNIT >> 1] = unitno & RX_M_NUMDR;
|
Bob Supnik | 2c2dd5e | 2002-11-17 15:54:00 -0800 | [diff] [blame] | 535 | M[BOOT_CSR >> 1] = rx_dib.ba & DMASK;
|
Mark Pizzolato | f0d41f1 | 2013-10-27 05:30:13 -0700 | [diff] [blame] | 536 | cpu_set_boot (BOOT_ENTRY);
|
Bob Supnik | 9af6fd2 | 2001-11-06 20:44:00 -0800 | [diff] [blame] | 537 | return SCPE_OK;
|
| 538 | }
|