| /* hp2100_dp.c: HP 2100 disk pack simulator | |
| Copyright (c) 1993-2000, Robert M. Supnik | |
| Permission is hereby granted, free of charge, to any person obtaining a | |
| copy of this software and associated documentation files (the "Software"), | |
| to deal in the Software without restriction, including without limitation | |
| the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| and/or sell copies of the Software, and to permit persons to whom the | |
| Software is furnished to do so, subject to the following conditions: | |
| The above copyright notice and this permission notice shall be included in | |
| all copies or substantial portions of the Software. | |
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | |
| IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
| CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
| Except as contained in this notice, the name of Robert M Supnik shall not | |
| be used in advertising or otherwise to promote the sale, use or other dealings | |
| in this Software without prior written authorization from Robert M Supnik. | |
| dp 12557A cartridge disk system | |
| */ | |
| #include "hp2100_defs.h" | |
| #define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */ | |
| #define UNIT_WLK (1 << UNIT_V_WLK) | |
| #define UNIT_W_UF 2 /* # flags */ | |
| #define FNC u3 /* saved function */ | |
| #define CYL u4 /* cylinder */ | |
| #define DP_W_NUMWD 7 | |
| #define DP_NUMWD (1 << DP_W_NUMWD) /* words/sector */ | |
| #define DP_NUMSC 12 /* sectors/track */ | |
| #define DP_NUMTR 203 /* tracks/surface */ | |
| #define DP_NUMSF 4 /* surfaces/track */ | |
| #define DP_SIZE (DP_NUMSF * DP_NUMTR * DP_NUMSC * DP_NUMWD) | |
| #define DP_NUMDRV 4 /* # drives */ | |
| /* Command word */ | |
| #define CW_V_FNC 12 /* function */ | |
| #define CW_M_FNC 017 | |
| #define CW_GETFNC(x) (((x) >> CW_V_FNC) & CW_M_FNC) | |
| #define FNC_STA 000 /* status check */ | |
| #define FNC_WD 001 /* write */ | |
| #define FNC_RD 002 /* read */ | |
| #define FNC_SEEK 003 /* seek */ | |
| #define FNC_REF 005 /* refine */ | |
| #define FNC_CHK 006 /* check */ | |
| #define FNC_INIT 011 /* init */ | |
| #define FNC_AR 013 /* address */ | |
| #define FNC_SEEK1 020 /* fake - seek1 */ | |
| #define FNC_SEEK2 021 /* fake - seek2 */ | |
| #define FNC_CHK1 022 /* fake - check1 */ | |
| #define FNC_AR1 023 /* fake - arec1 */ | |
| #define CW_V_DRV 0 /* drive */ | |
| #define CW_M_DRV 03 | |
| #define CW_GETDRV(x) (((x) >> CW_V_DRV) & CW_M_DRV) | |
| /* Disk address words */ | |
| #define DA_V_CYL 0 /* cylinder */ | |
| #define DA_M_CYL 0377 | |
| #define DA_GETCYL(x) (((x) >> DA_V_CYL) & DA_M_CYL) | |
| #define DA_V_HD 8 /* head */ | |
| #define DA_M_HD 03 | |
| #define DA_GETHD(x) (((x) >> DA_V_HD) & DA_M_HD) | |
| #define DA_V_SC 0 /* sector */ | |
| #define DA_M_SC 017 | |
| #define DA_GETSC(x) (((x) >> DA_V_SC) & DA_M_SC) | |
| /* Status */ | |
| #define STA_ATN 0100000 /* attention */ | |
| #define STA_1ST 0040000 /* first seek */ | |
| #define STA_OVR 0020000 /* overrun */ | |
| #define STA_RWU 0010000 /* rw unsafe */ | |
| #define STA_ACU 0004000 /* access unsafe */ | |
| #define STA_HUNT 0002000 /* hunting */ | |
| #define STA_SKI 0001000 /* incomplete */ | |
| #define STA_SKE 0000400 /* seek error */ | |
| /* 0000200 /* unused */ | |
| #define STA_NRDY 0000100 /* not ready */ | |
| #define STA_EOC 0000040 /* end of cylinder */ | |
| #define STA_AER 0000020 /* addr error */ | |
| #define STA_FLG 0000010 /* flagged */ | |
| #define STA_BSY 0000004 /* seeking */ | |
| #define STA_DTE 0000002 /* data error */ | |
| #define STA_ERR 0000001 /* any error */ | |
| #define STA_ALLERR (STA_ATN + STA_1ST + STA_OVR + STA_RWU + STA_ACU + \ | |
| STA_HUNT + STA_SKI + STA_SKE + STA_NRDY + STA_EOC + \ | |
| STA_FLG + STA_DTE) | |
| extern unsigned int16 M[]; | |
| extern struct hpdev infotab[]; | |
| extern int32 PC; | |
| extern int32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2]; | |
| int32 dpc_busy = 0; /* cch busy */ | |
| int32 dpc_cnt = 0; /* check count */ | |
| int32 dpc_eoc = 0; /* end of cyl */ | |
| int32 dpc_sta[DP_NUMDRV] = { 0 }; /* status regs */ | |
| int32 dpc_stime = 10; /* seek time */ | |
| int32 dpc_ctime = 10; /* command time */ | |
| int32 dpc_xtime = 5; /* xfer time */ | |
| int32 rarc = 0, rarh = 0, rars = 0; /* record addr */ | |
| int32 dpd_obuf = 0, dpd_ibuf = 0; /* dch buffers */ | |
| int32 dpc_obuf = 0; /* cch buffers */ | |
| int32 dpbptr = 0; /* buffer ptr */ | |
| unsigned int16 dbuf[DP_NUMWD]; /* sector buffer */ | |
| t_stat dpc_svc (UNIT *uptr); | |
| t_stat dpc_reset (DEVICE *dptr); | |
| t_stat dpc_vlock (UNIT *uptr, int32 val); | |
| t_stat dpc_attach (UNIT *uptr, char *cptr); | |
| t_stat dpc_detach (UNIT *uptr); | |
| t_stat dpd_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); | |
| t_stat dpd_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); | |
| void dp_go (int32 fnc, int32 drv, int32 time, int32 attdev); | |
| extern t_bool hp_setdev2 (UNIT *uptr, int32 val); | |
| /* DPD data structures | |
| dpd_dev DPD device descriptor | |
| dpd_unit DPD unit list | |
| dpd_reg DPD register list | |
| */ | |
| UNIT dpd_unit = { UDATA (NULL, UNIT_FIX, DP_NUMWD) }; | |
| REG dpd_reg[] = { | |
| { ORDATA (IBUF, dpd_ibuf, 16) }, | |
| { ORDATA (OBUF, dpd_obuf, 16) }, | |
| { FLDATA (CMD, infotab[inDPD].cmd, 0) }, | |
| { FLDATA (CTL, infotab[inDPD].ctl, 0) }, | |
| { FLDATA (FLG, infotab[inDPD].flg, 0) }, | |
| { FLDATA (FBF, infotab[inDPD].fbf, 0) }, | |
| { DRDATA (BPTR, dpbptr, DP_W_NUMWD) }, | |
| { ORDATA (DEVNO, infotab[inDPD].devno, 6), REG_RO }, | |
| { NULL } }; | |
| DEVICE dpd_dev = { | |
| "DPD", &dpd_unit, dpd_reg, NULL, | |
| 1, 10, DP_W_NUMWD, 1, 8, 16, | |
| &dpd_ex, &dpd_dep, &dpc_reset, | |
| NULL, NULL, NULL }; | |
| /* DPC data structures | |
| dpc_dev DPC device descriptor | |
| dpc_unit DPC unit list | |
| dpc_reg DPC register list | |
| dpc_mod DPC modifier list | |
| */ | |
| UNIT dpc_unit[] = { | |
| { UDATA (&dpc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DP_SIZE) }, | |
| { UDATA (&dpc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DP_SIZE) }, | |
| { UDATA (&dpc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DP_SIZE) }, | |
| { UDATA (&dpc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DP_SIZE) } }; | |
| REG dpc_reg[] = { | |
| { ORDATA (OBUF, dpc_obuf, 16) }, | |
| { ORDATA (BUSY, dpc_busy, 3), REG_RO }, | |
| { ORDATA (RARC, rarc, 8) }, | |
| { ORDATA (RARH, rarh, 2) }, | |
| { ORDATA (RARS, rars, 4) }, | |
| { ORDATA (CNT, dpc_cnt, 5) }, | |
| { FLDATA (CMD, infotab[inDPC].cmd, 0) }, | |
| { FLDATA (CTL, infotab[inDPC].ctl, 0) }, | |
| { FLDATA (FLG, infotab[inDPC].flg, 0) }, | |
| { FLDATA (FBF, infotab[inDPC].fbf, 0) }, | |
| { FLDATA (EOC, dpc_eoc, 0) }, | |
| { DRDATA (CTIME, dpc_ctime, 24), PV_LEFT }, | |
| { DRDATA (STIME, dpc_stime, 24), PV_LEFT }, | |
| { DRDATA (XTIME, dpc_xtime, 24), REG_NZ + PV_LEFT }, | |
| { ORDATA (STA0, dpc_sta[0], 16) }, | |
| { ORDATA (STA1, dpc_sta[1], 16) }, | |
| { ORDATA (STA2, dpc_sta[2], 16) }, | |
| { ORDATA (STA3, dpc_sta[3], 16) }, | |
| { GRDATA (UFLG0, dpc_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), | |
| REG_HRO }, | |
| { GRDATA (UFLG1, dpc_unit[1].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), | |
| REG_HRO }, | |
| { GRDATA (UFLG2, dpc_unit[2].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), | |
| REG_HRO }, | |
| { GRDATA (UFLG3, dpc_unit[3].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), | |
| REG_HRO }, | |
| { ORDATA (DEVNO, infotab[inDPC].devno, 6), REG_RO }, | |
| { NULL } }; | |
| MTAB dpc_mod[] = { | |
| /* { UNIT_WLK, 0, "write enabled", "ENABLED", &dpc_vlock }, */ | |
| /* { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", &dpc_vlock }, */ | |
| { UNIT_DEVNO, inDPD, NULL, "DEVNO", &hp_setdev2 }, | |
| { 0 } }; | |
| DEVICE dpc_dev = { | |
| "DPC", dpc_unit, dpc_reg, dpc_mod, | |
| DP_NUMDRV, 8, 24, 1, 8, 16, | |
| NULL, NULL, &dpc_reset, | |
| NULL, &dpc_attach, &dpc_detach }; | |
| /* IOT routines */ | |
| int32 dpdio (int32 inst, int32 IR, int32 dat) | |
| { | |
| int32 devd; | |
| devd = IR & DEVMASK; /* get device no */ | |
| switch (inst) { /* case on opcode */ | |
| case ioFLG: /* flag clear/set */ | |
| if ((IR & HC) == 0) { setFLG (devd); } /* STF */ | |
| break; | |
| case ioSFC: /* skip flag clear */ | |
| if (FLG (devd) == 0) PC = (PC + 1) & AMASK; | |
| return dat; | |
| case ioSFS: /* skip flag set */ | |
| if (FLG (devd) != 0) PC = (PC + 1) & AMASK; | |
| return dat; | |
| case ioOTX: /* output */ | |
| dpd_obuf = dat; | |
| break; | |
| case ioMIX: /* merge */ | |
| dat = dat | dpd_ibuf; | |
| break; | |
| case ioLIX: /* load */ | |
| dat = dpd_ibuf; | |
| break; | |
| case ioCTL: /* control clear/set */ | |
| if (IR & AB) { /* CLC */ | |
| clrCTL (devd); /* clr ctl, cmd */ | |
| clrCMD (devd); } | |
| else { setCTL (devd); /* STC */ | |
| setCMD (devd); } /* set ctl, cmd */ | |
| break; | |
| default: | |
| break; } | |
| if (IR & HC) { clrFLG (devd); } /* H/C option */ | |
| return dat; | |
| } | |
| int32 dpcio (int32 inst, int32 IR, int32 dat) | |
| { | |
| int32 i, devc, fnc, drv; | |
| devc = IR & DEVMASK; /* get device no */ | |
| switch (inst) { /* case on opcode */ | |
| case ioFLG: /* flag clear/set */ | |
| if ((IR & HC) == 0) { setFLG (devc); } /* STF */ | |
| break; | |
| case ioSFC: /* skip flag clear */ | |
| if (FLG (devc) == 0) PC = (PC + 1) & AMASK; | |
| return dat; | |
| case ioSFS: /* skip flag set */ | |
| if (FLG (devc) != 0) PC = (PC + 1) & AMASK; | |
| return dat; | |
| case ioOTX: /* output */ | |
| dpc_obuf = dat; | |
| break; | |
| case ioLIX: /* load */ | |
| dat = 0; | |
| case ioMIX: /* merge */ | |
| for (i = 0; i < DP_NUMDRV; i++) | |
| if (dpc_sta[i] & STA_ATN) dat = dat | (1 << i); | |
| break; | |
| case ioCTL: /* control clear/set */ | |
| if (IR & AB) { /* CLC? */ | |
| clrCMD (devc); /* clr cmd, ctl */ | |
| clrCTL (devc); /* cancel non-seek */ | |
| if (dpc_busy) sim_cancel (&dpc_unit[dpc_busy - 1]); | |
| dpc_busy = 0; } /* clr busy */ | |
| else if (!CTL (devc)) { /* set and now clr? */ | |
| setCMD (devc); /* set cmd, ctl */ | |
| setCTL (devc); | |
| drv = CW_GETDRV (dpc_obuf); /* get fnc, drv */ | |
| fnc = CW_GETFNC (dpc_obuf); /* from cmd word */ | |
| switch (fnc) { /* case on fnc */ | |
| case FNC_SEEK: /* seek */ | |
| dpc_sta[drv] = (dpc_sta[drv] | STA_BSY) & | |
| ~(STA_SKE | STA_SKI | STA_HUNT | STA_1ST); | |
| dp_go (fnc, drv, dpc_xtime, devc); | |
| break; | |
| case FNC_STA: case FNC_AR: /* rd sta, addr rec */ | |
| dp_go (fnc, drv, dpc_xtime, 0); | |
| break; | |
| case FNC_CHK: /* check */ | |
| dp_go (fnc, drv, dpc_xtime, devc); | |
| break; | |
| case FNC_REF: case FNC_RD: case FNC_WD: /* ref, read, write */ | |
| dp_go (fnc, drv, dpc_ctime, devc); | |
| break; | |
| case FNC_INIT: /* init */ | |
| dpc_sta[drv] = dpc_sta[drv] | STA_FLG; | |
| setFLG (devc); /* set cch flg */ | |
| clrCMD (devc); /* clr cch cmd */ | |
| break; | |
| } /* end case */ | |
| } /* end else */ | |
| break; | |
| default: | |
| break; } | |
| if (IR & HC) { clrFLG (devc); } /* H/C option */ | |
| return dat; | |
| } | |
| /* Unit service | |
| Unit must be attached; detach cancels operation. | |
| Seek substates | |
| seek - transfer cylinder | |
| seek1 - transfer head/surface | |
| seek2 - done | |
| Address record | |
| ar - transfer cylinder | |
| ar1 - transfer head/surface, finish operation | |
| Status check - transfer status, finish operation | |
| Refine sector - erase sector, finish operation | |
| Check data | |
| chk - transfer sector count | |
| chk1 - finish operation | |
| Read | |
| Write | |
| */ | |
| #define GETDA(x,y,z) \ | |
| (((((x) * DP_NUMSF) + (y)) * DP_NUMSC) + (z)) * DP_NUMWD | |
| t_stat dpc_svc (UNIT *uptr) | |
| { | |
| int32 i, da, drv, devc, devd, err, st, maxsc; | |
| err = 0; /* assume no err */ | |
| drv = uptr - dpc_dev.units; /* get drive no */ | |
| devc = infotab[inDPC].devno; /* get cch devno */ | |
| devd = infotab[inDPD].devno; /* get dch devno */ | |
| switch (uptr -> FNC) { /* case function */ | |
| case FNC_SEEK: /* seek, need cyl */ | |
| if (CMD (devd)) { /* dch active? */ | |
| rarc = DA_GETCYL (dpd_obuf); /* take cyl word */ | |
| setFLG (devd); /* set dch flg */ | |
| clrCMD (devd); /* clr dch cmd */ | |
| uptr -> FNC = FNC_SEEK1; } /* advance state */ | |
| sim_activate (uptr, dpc_xtime); /* no, wait more */ | |
| return SCPE_OK; | |
| case FNC_SEEK1: /* seek, need hd/sec */ | |
| if (CMD (devd)) { /* dch active? */ | |
| rarh = DA_GETHD (dpd_obuf); /* get head */ | |
| rars = DA_GETSC (dpd_obuf); /* get sector */ | |
| setFLG (devd); /* set dch flg */ | |
| clrCMD (devd); /* clr dch cmd */ | |
| st = abs (rarc - uptr -> CYL) * dpc_stime; /* calc cyl diff */ | |
| if (st == 0) st = dpc_xtime; /* min time */ | |
| sim_activate (uptr, st); /* schedule op */ | |
| uptr -> CYL = rarc; /* on cylinder */ | |
| dpc_busy = 0; /* ctrl is free */ | |
| uptr -> FNC = FNC_SEEK2; } /* advance state */ | |
| else sim_activate (uptr, dpc_xtime); /* no, wait more */ | |
| return SCPE_OK; | |
| case FNC_SEEK2: /* seek done */ | |
| if (dpc_busy) sim_activate (uptr, dpc_xtime); /* ctrl busy? wait */ | |
| else { dpc_sta[drv] = (dpc_sta[drv] | STA_ATN) & ~STA_BSY; | |
| if (uptr -> CYL >= DP_NUMTR) { /* error? */ | |
| dpc_sta[drv] = dpc_sta[drv] | STA_SKE; | |
| uptr -> CYL = 0; } | |
| setFLG (devc); /* set cch flg */ | |
| clrCMD (devc); } /* clr cch cmd */ | |
| return SCPE_OK; | |
| case FNC_AR: /* arec, need cyl */ | |
| if (CMD (devd)) { /* dch active? */ | |
| rarc = DA_GETCYL (dpd_obuf); /* take cyl word */ | |
| setFLG (devd); /* set dch flg */ | |
| clrCMD (devd); /* clr dch cmd */ | |
| uptr -> FNC = FNC_AR1; } /* advance state */ | |
| sim_activate (uptr, dpc_xtime); /* no, wait more */ | |
| return SCPE_OK; | |
| case FNC_AR1: /* arec, need hd/sec */ | |
| if (CMD (devd)) { /* dch active? */ | |
| rarh = DA_GETHD (dpd_obuf); /* get head */ | |
| rars = DA_GETSC (dpd_obuf); /* get sector */ | |
| setFLG (devd); /* set dch flg */ | |
| clrCMD (devd); } /* clr dch cmd */ | |
| else { sim_activate (uptr, dpc_xtime); /* no, wait more */ | |
| return SCPE_OK; } | |
| break; /* done */ | |
| case FNC_STA: /* read status */ | |
| if (CMD (devd)) { /* dch active? */ | |
| dpd_ibuf = dpc_sta[drv] | ((dpc_sta[drv] & STA_ALLERR)? STA_ERR: 0); | |
| setFLG (devd); /* set dch flg */ | |
| clrCMD (devd); /* clr dch cmd */ | |
| dpc_sta[drv] = dpc_sta[drv] & /* clr sta flags */ | |
| ~(STA_ATN | STA_DTE | STA_FLG | STA_AER | STA_EOC); | |
| dpc_busy = 0; } /* ctlr is free */ | |
| else sim_activate (uptr, dpc_xtime); /* wait more */ | |
| return SCPE_OK; | |
| case FNC_REF: /* refine sector */ | |
| if ((uptr -> CYL != rarc) || (rars >= DP_NUMSC)) | |
| dpc_sta[drv] = dpc_sta[drv] | STA_AER; | |
| else { for (i = 0; i < DP_NUMWD; i++) dbuf[i] = 0; | |
| da = GETDA (rarc, rarh, rars); /* get address */ | |
| rars = rars + 1; /* incr sector */ | |
| if (rars >= DP_NUMSC) { /* end of trk? */ | |
| rars = 0; /* wrap to */ | |
| rarh = rarh ^ 1; } /* next surf */ | |
| if (err = fseek (uptr -> fileref, da * sizeof (int16), | |
| SEEK_SET)) break; | |
| fxwrite (dbuf, sizeof (int16), DP_NUMWD, uptr -> fileref); | |
| err = ferror (uptr -> fileref); } | |
| break; | |
| case FNC_CHK: /* check, need cnt */ | |
| if (CMD (devd)) { /* dch active? */ | |
| dpc_cnt = dpd_obuf & 037; /* get count */ | |
| setFLG (devd); /* set dch flg */ | |
| clrCMD (devd); /* clr dch cmd */ | |
| sim_activate (uptr, dpc_ctime); /* schedule op */ | |
| uptr -> FNC = FNC_CHK1; } /* advance state */ | |
| else sim_activate (uptr, dpc_xtime); /* wait more */ | |
| return SCPE_OK; | |
| case FNC_CHK1: | |
| if ((uptr -> CYL != rarc) || (rars >= DP_NUMSC)) | |
| dpc_sta[drv] = dpc_sta[drv] | STA_AER; | |
| else { maxsc = ((2 - (rarh & 1)) * DP_NUMSC) - rars; | |
| if (dpc_cnt > maxsc) { /* too many sec? */ | |
| dpc_sta[drv] = dpc_sta[drv] | STA_EOC; | |
| rarh = rarh & ~1; /* rar = 0/2, 0 */ | |
| rars = 0; } | |
| else { i = rars + dpc_cnt; /* final sector */ | |
| rars = i % DP_NUMSC; /* reposition */ | |
| rarh = rarh ^ ((i / DP_NUMSC) & 1); } } | |
| break; /* done */ | |
| case FNC_RD: /* read */ | |
| if (!CMD (devd)) break; /* dch clr? done */ | |
| if (FLG (devd)) dpc_sta[drv] = dpc_sta[drv] | STA_OVR; | |
| if (dpbptr == 0) { /* new sector? */ | |
| if ((uptr -> CYL != rarc) || (rars >= DP_NUMSC)) { | |
| dpc_sta[drv] = dpc_sta[drv] | STA_AER; | |
| break; } | |
| if (dpc_eoc) { /* end of cyl? */ | |
| dpc_sta[drv] = dpc_sta[drv] | STA_EOC; | |
| break; } | |
| da = GETDA (rarc, rarh, rars); /* get address */ | |
| rars = rars + 1; /* incr address */ | |
| if (rars >= DP_NUMSC) { /* end of trk? */ | |
| rars = 0; /* wrap to */ | |
| rarh = rarh ^ 1; /* next cyl */ | |
| dpc_eoc = ((rarh & 1) == 0); } /* calc eoc */ | |
| if (err = fseek (uptr -> fileref, da * sizeof (int16), | |
| SEEK_SET)) break; | |
| fxread (dbuf, sizeof (int16), DP_NUMWD, uptr -> fileref); | |
| if (err = ferror (uptr -> fileref)) break; } | |
| dpd_ibuf = dbuf[dpbptr++]; /* get word */ | |
| if (dpbptr >= DP_NUMWD) dpbptr = 0; /* wrap if last */ | |
| setFLG (devd); /* set dch flg */ | |
| clrCMD (devd); /* clr dch cmd */ | |
| sim_activate (uptr, dpc_xtime); /* sched next word */ | |
| return SCPE_OK; | |
| case FNC_WD: /* write */ | |
| if (dpc_eoc) { /* end of cyl? */ | |
| dpc_sta[drv] = dpc_sta[drv] | STA_EOC; /* set status */ | |
| break; } /* done */ | |
| if (FLG (devd)) dpc_sta[drv] = dpc_sta[drv] | STA_OVR; | |
| dbuf[dpbptr++] = dpd_obuf; /* store word */ | |
| if (!CMD (devd)) { /* dch clr? done */ | |
| for ( ; dpbptr < DP_NUMWD; dpbptr++) dbuf[dpbptr] = 0; } | |
| if (dpbptr >= DP_NUMWD) { /* buffer full? */ | |
| if ((uptr -> CYL != rarc) || (rars >= DP_NUMSC)) { | |
| dpc_sta[drv] = dpc_sta[drv] | STA_AER; | |
| break; } | |
| da = GETDA (rarc, rarh, rars); /* get address */ | |
| rars = rars + 1; /* incr address */ | |
| if (rars >= DP_NUMSC) { /* end of trk? */ | |
| rars = 0; /* wrap to */ | |
| rarh = rarh ^ 1; /* next cyl */ | |
| dpc_eoc = ((rarh & 1) == 0); } /* calc eoc */ | |
| if (err = fseek (uptr -> fileref, da * sizeof (int16), | |
| SEEK_SET)) return TRUE; | |
| fwrite (dbuf, sizeof (int16), DP_NUMWD, uptr -> fileref); | |
| if (err = ferror (uptr -> fileref)) break; | |
| dpbptr = 0; } | |
| if (CMD (devd)) { /* dch active? */ | |
| setFLG (devd); /* set dch flg */ | |
| clrCMD (devd); /* clr dch cmd */ | |
| sim_activate (uptr, dpc_xtime); /* sched next word */ | |
| return SCPE_OK; } | |
| break; } /* end case fnc */ | |
| dpc_sta[drv] = dpc_sta[drv] | STA_ATN; /* request attn */ | |
| setFLG (devc); /* set cch flg */ | |
| clrCMD (devc); /* clr cch cmd */ | |
| dpc_busy = 0; /* ctlr is free */ | |
| if (err != 0) { /* error? */ | |
| perror ("DP I/O error"); | |
| clearerr (uptr -> fileref); | |
| return SCPE_IOERR; } | |
| return SCPE_OK; | |
| } | |
| /* Start disk operation */ | |
| void dp_go (int32 fnc, int32 drv, int32 time, int32 dev) | |
| { | |
| if (dev && ((dpc_unit[drv].flags & UNIT_ATT) == 0)) { /* attach check? */ | |
| dpc_sta[drv] = STA_NRDY; /* not attached */ | |
| setFLG (dev); /* set cch flag */ | |
| clrCMD (dev); } /* clr cch cmd */ | |
| else { dpc_busy = drv + 1; /* set busy */ | |
| dpbptr = 0; /* init buf ptr */ | |
| dpc_eoc = 0; /* clear end cyl */ | |
| dpc_unit[drv].FNC = fnc; /* save function */ | |
| sim_activate (&dpc_unit[drv], time); } /* activate unit */ | |
| return; | |
| } | |
| /* Reset routine */ | |
| t_stat dpc_reset (DEVICE *dptr) | |
| { | |
| int32 i; | |
| dpd_ibuf = dpd_obuf = 0; /* clear buffers */ | |
| dpc_busy = dpc_obuf = 0; | |
| dpc_eoc = 0; | |
| dpbptr = 0; | |
| rarc = rarh = rars = 0; /* clear rar */ | |
| infotab[inDPC].cmd = infotab[inDPD].cmd = 0; /* clear cmd */ | |
| infotab[inDPC].ctl = infotab[inDPD].ctl = 0; /* clear ctl */ | |
| infotab[inDPC].fbf = infotab[inDPD].fbf = 0; /* clear flg */ | |
| infotab[inDPC].flg = infotab[inDPD].flg = 0; /* clear fbf */ | |
| for (i = 0; i < DP_NUMDRV; i++) { /* loop thru drives */ | |
| sim_cancel (&dpc_unit[i]); /* cancel activity */ | |
| dpc_unit[i].FNC = 0; /* clear function */ | |
| dpc_unit[i].CYL = 0; | |
| dpc_sta[i] = (dpc_sta[i] & STA_1ST) | | |
| ((dpc_unit[i].flags & UNIT_ATT)? 0: STA_NRDY); } | |
| return SCPE_OK; | |
| } | |
| /* Attach routine */ | |
| t_stat dpc_attach (UNIT *uptr, char *cptr) | |
| { | |
| int32 drv; | |
| t_stat r; | |
| drv = uptr - dpc_dev.units; /* get drive no */ | |
| r = attach_unit (uptr, cptr); /* attach unit */ | |
| if (r != SCPE_OK) return r; | |
| dpc_sta[drv] = (dpc_sta[drv] | STA_1ST) & ~STA_NRDY; /* update status */ | |
| return r; | |
| } | |
| /* Detach routine */ | |
| t_stat dpc_detach (UNIT* uptr) | |
| { | |
| int32 drv; | |
| drv = uptr - dpc_dev.units; /* get drive no */ | |
| dpc_sta[drv] = (dpc_sta[drv] | STA_NRDY) & ~STA_1ST; /* update status */ | |
| if (drv == (dpc_busy + 1)) dpc_busy = 0; /* update busy */ | |
| sim_cancel (uptr); /* cancel op */ | |
| return detach_unit (uptr); /* detach unit */ | |
| } | |
| /* Write lock/enable routine */ | |
| t_stat dpc_vlock (UNIT *uptr, int32 val) | |
| { | |
| if (uptr -> flags & UNIT_ATT) return SCPE_ARG; | |
| return SCPE_OK; | |
| } | |
| /* Buffer examine */ | |
| t_stat dpd_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) | |
| { | |
| if (addr >= DP_NUMWD) return SCPE_NXM; | |
| if (vptr != NULL) *vptr = dbuf[addr] & DMASK; | |
| return SCPE_OK; | |
| } | |
| /* Buffer deposit */ | |
| t_stat dpd_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) | |
| { | |
| if (addr >= DP_NUMWD) return SCPE_NXM; | |
| dbuf[addr] = val & DMASK; | |
| return SCPE_OK; | |
| } |