RESTRICTION: The FP15 and XVM features of the PDP-15 are only partially debugged. Do NOT enable these features for normal operations. 1. New Features in 3.1-0 1.1 SCP and libraries - Added simulated Ethernet support for VMS, FreeBSD, Mac OS/X. - Added status return to tmxr_putc_ln. - Added sim_putchar_s to handle possible output stalls. 1.2 All DECtapes - Added "DECtape off reel" error stop. 1.3 All Asynchronous Consoles - Added support for output congestion stall if using a Telnet connection. 1.4 PDP-1 - Added Type 23 parallel drum support. 1.5 PDP-8 - Added instruction history. - Added TSC8-75 option support for ETOS. - Added TD8E DECtape support. 1.6 PDP-18b - Added instruction history. - Changed PDP-9, PDP-15 API default to enabled. 1.7 PDP-11 - Added support for 18b only Qbus devices. - Formalized bus and addressing definitions. - Added control to enable/disable autoconfiguration. - Added stub support for second Unibus Ethernet controller. 1.7 Interdata 32b - Added instruction history. 1.8 Eclipse - Added floating point support. - Added programmable interval timer support. 1.9 H316 - Added DMA/DMC support. - Added fixed head disk support. - Added moving head disk support. - Added magtape support. 1.10 IBM 1130 (Brian Knittel) - Added support for physical card reader, using the Cardread interface (www.ibm1130.org/sim/downloads). - Added support for physical printer (flushes output buffer after each line). 2. Bugs Fixed in 3.1-0 2.1 SCP and libraries - Fixed numerous bugs in Ethernet library. 2.2 All DECtapes - Fixed reverse checksum value in 'read all' mode. - Simplified (and sped up) timing. 2.3 PDP-8 - Fixed bug in RX28 read status (found by Charles Dickman). - Fixed RX28 double density write. 2.4 PDP-18b - Fixed autoincrement bug in PDP-4, PDP-7, PDP-9. 2.5 PDP-11/VAX - Revised RQ MB->LBN conversion for greater accuracy. - Fixed bug in IO configuration (found by David Hittner). - Fixed bug with multiple RQ RAUSER drives. - Fixed bug in second Qbus Ethernet controller interrupts. 2.6 Nova/Eclipse - Fixed bugs in DKP flag clear, map setup, map usage (Charles Owen). - Fixed bug in MT, reset completes despite I/O reset (Charles Owen). - Fixed bug in MT, space operations return word count (Charles Owen). 2.7 IBM 1130 (Brian Knittel) - Fixed bug in setting carry bit in subtract and subtract double. - Fixed timing problem in console printer simulation. 2.8 1620 - Fixed bug in branch digit (found by Dave Babcock). 3. New Features in 3.0 vs prior releases 3.1 SCP and Libraries - Added ASSIGN/DEASSIGN (logical name) commands. - Changed RESTORE to unconditionally detach files. - Added E11 and TPC format support to magtape library. - Fixed bug in SHOW CONNECTIONS. - Added USE_ADDR64 support. 3.2 All magtapes - Magtapes support SIMH format, E11 format, and TPC format (read only). - SET <tape_unit> FORMAT=format sets the specified tape unit's format. - SHOW <tape_unit> FORMAT displays the specified tape unit's format. - Tape format can also be set as part of the ATTACH command, using the -F switch. 3.3 VAX - VAX can be compiled without USE_INT64. - If compiled with USE_INT64 and USE_ADDR64, RQ and TQ controllers support files > 2GB. - VAX ROM has speed control (SET ROM DELAY/NODELAY). 3.4 PDP-1 - Added block loader format support to LOAD. - Changed BOOT PTR to allow loading of all of the first bank of memory. - The LOAD command takes an optional argument specifying the memory field to be loaded. - The PTR BOOT command takes its starting memory field from the TA (address switch) register. 3.5 PDP-18b Family - Added PDP-4 EAE support. - Added PDP-15 FP15 support. - Added PDP-15 XVM support. - Added PDP-15 "re-entrancy ECO". - Added PDP-7, PDP-9, PDP-15 hardware RIM loader support in BOOT PTR. 4. Bugs Fixed in 3.0 vs prior releases 4.1 SCP and Libraries - Fixed end of file problem in dep, idep. - Fixed handling of trailing spaces in dep, idep. 4.2 VAX - Fixed CVTfi bug: integer overflow not set if exponent out of range - Fixed EMODx bugs: o First and second operands reversed o Separated fraction received wrong exponent o Overflow calculation on separated integer incorrect o Fraction not set to zero if exponent out of range - Fixed interval timer and ROM access to pass power-up self-test even on very fast host processors (fixes from Mark Pizzolato). - Fixed bug in user disk size (found by Chaskiel M Grundman). 4.3 1401 - Fixed mnemonic, instruction lengths, and reverse scan length check bug for MCS. - Fixed MCE bug, BS off by 1 if zero suppress. - Fixed chaining bug, D lost if return to SCP. - Fixed H branch, branch occurs after continue. - Added check for invalid 8 character MCW, LCA. - Fixed magtape load-mode end of record response. - Revised fetch to model hardware more closely. - Fixed tape read end-of-record handling based on real 1401. - Added diagnostic read (space forward). 4.4 Nova - Fixed DSK variable size interaction with restore. - Fixed bug in DSK set size routine. 4.5 PDP-1 - Fixed DT variable size interaction with restore. - Updated CPU, line printer, standard devices to detect indefinite I/O wait. - Fixed incorrect logical, missing activate, break in drum simulator. - Fixed bugs in instruction decoding, overprinting for line printer. - Fixed system hang if continue after PTR error. - Fixed PTR to start/stop on successive rpa instructions. 4.6 PDP-11 - Fixed DT variable size interaction with restore. - Fixed bug in MMR1 update (found by Tim Stark). - Added XQ features and fixed bugs: o Corrected XQ interrupts on IE state transition (code by Tom Evans). o Added XQ interrupt clear on soft reset. o Removed XQ interrupt when setting XL or RL (multiple people). o Added SET/SHOW XQ STATS. o Added SHOW XQ FILTERS. o Added ability to split received packet into multiple buffers. o Added explicit runt and giant packet processing. - Fixed bug in user disk size (found by Chaskiel M Grundman). 4.7 PDP-18B - Fixed DT, RF variable size interaction with restore. - Fixed MT bug in MTTR. - Fixed bug in PDP-4 line printer overprinting. - Fixed bug in PDP-15 memory protect/skip interaction. - Fixed bug in RF set size routine. - Increased PTP TIME for PDP-15 operating systems. - Fixed priorities in PDP-15 API (differs from PDP-9). - Fixed sign handling in PDP-15 EAE unsigned mul/div (differs from PDP-9). - Fixed bug in CAF, clears API subsystem. 4.8 PDP-8 - Fixed DT, DF, RF, RX variable size interaction with restore. - Fixed MT bug in SKTR. - Fixed bug in DF, RF set size routine. 4.9 HP2100 - Fixed bug in DP (13210A controller only), DQ read status. - Fixed bug in DP, DQ seek complete. - Fixed DR drum sizes. - Fixed DR variable capacity interaction with SAVE/RESTORE. 4.10 GRI - Fixed bug in SC queue pointer management. 4.11 PDP-10 - Fixed bug in RP read header. 4.12 Ibm1130 - Fixed bugs found by APL 1130. 4.13 Altairz80 - Fixed bug in real-time clock on Windows host. 4.14 1620 - Fixed bug in immediate index add (found by Michael Short).
423 lines
14 KiB
C
423 lines
14 KiB
C
/* h316_fhd.c: H316/516 fixed head simulator
|
||
|
||
Copyright (c) 2003, 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.
|
||
|
||
fhd 516-4400 fixed head disk
|
||
|
||
These head-per-track devices are buffered in memory, to minimize overhead.
|
||
*/
|
||
|
||
#include "h316_defs.h"
|
||
#include <math.h>
|
||
|
||
/* Constants */
|
||
|
||
#define FH_NUMWD 1536 /* words/track */
|
||
#define FH_NUMTK 64 /* tracks/surface */
|
||
#define FH_WDPSF (FH_NUMWD * FH_NUMTK) /* words/surface */
|
||
#define FH_NUMSF 16 /* surfaces/ctlr */
|
||
#define UNIT_V_AUTO (UNIT_V_UF + 0) /* autosize */
|
||
#define UNIT_V_SF (UNIT_V_UF + 1) /* #surfaces - 1 */
|
||
#define UNIT_M_SF 017
|
||
#define UNIT_AUTO (1 << UNIT_V_AUTO)
|
||
#define UNIT_SF (UNIT_M_SF << UNIT_V_SF)
|
||
#define UNIT_GETSF(x) ((((x) >> UNIT_V_SF) & UNIT_M_SF) + 1)
|
||
|
||
/* Command word 1 */
|
||
|
||
#define CW1_RW 0100000 /* read vs write */
|
||
#define CW1_V_SF 10 /* surface */
|
||
#define CW1_M_SF 017
|
||
#define CW1_GETSF(x) (((x) >> CW1_V_SF) & CW1_M_SF)
|
||
#define CW1_V_TK 4 /* track */
|
||
#define CW1_M_TK 077
|
||
#define CW1_GETTK(x) (((x) >> CW1_V_TK) & CW1_M_TK)
|
||
|
||
/* Command word 2 */
|
||
|
||
#define CW2_V_CA 0 /* character addr */
|
||
#define CW2_M_CA 07777
|
||
#define CW2_GETCA(x) (((x) >> CW2_V_CA) & CW2_M_CA)
|
||
|
||
#define GET_POS(x) ((int) fmod (sim_gtime() / ((double) (x)), \
|
||
((double) FH_NUMWD)))
|
||
|
||
/* OTA states */
|
||
|
||
#define OTA_NOP 0 /* normal */
|
||
#define OTA_CW1 1 /* expecting CW1 */
|
||
#define OTA_CW2 2 /* expecting CW2 */
|
||
|
||
extern int32 dev_int, dev_enb, chan_req;
|
||
extern int32 stop_inst;
|
||
extern uint32 dma_ad[DMA_MAX];
|
||
|
||
uint32 fhd_cw1 = 0; /* cmd word 1 */
|
||
uint32 fhd_cw2 = 0; /* cmd word 2 */
|
||
uint32 fhd_buf = 0; /* buffer */
|
||
uint32 fhd_otas = 0; /* state */
|
||
uint32 fhd_busy = 0; /* busy */
|
||
uint32 fhd_rdy = 0; /* word ready */
|
||
uint32 fhd_dte = 0; /* data err */
|
||
uint32 fhd_ace = 0; /* access error */
|
||
uint32 fhd_dma = 0; /* DMA/DMC */
|
||
uint32 fhd_eor = 0; /* end of range */
|
||
uint32 fhd_csum = 0; /* parity checksum */
|
||
uint32 fhd_stopioe = 1; /* stop on error */
|
||
int32 fhd_time = 10; /* time per word */
|
||
|
||
int32 fhdio (int32 inst, int32 fnc, int32 dat, int32 dev);
|
||
t_stat fhd_svc (UNIT *uptr);
|
||
t_stat fhd_reset (DEVICE *dptr);
|
||
t_stat fhd_attach (UNIT *uptr, char *cptr);
|
||
t_stat fhd_boot (int32 unitno, DEVICE *dptr);
|
||
t_stat fhd_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
|
||
void fhd_go (uint32 dma);
|
||
void fhd_go1 (uint32 dat);
|
||
void fhd_go2 (uint32 dat);
|
||
t_bool fhd_getc (UNIT *uptr, uint32 *ch);
|
||
t_bool fhd_putc (UNIT *uptr, uint32 ch);
|
||
t_bool fhd_bad_wa (uint32 wa);
|
||
uint32 fhd_csword (uint32 cs, uint32 ch);
|
||
|
||
/* FHD data structures
|
||
|
||
fhd_dev device descriptor
|
||
fhd_unit unit descriptor
|
||
fhd_mod unit modifiers
|
||
fhd_reg register list
|
||
*/
|
||
|
||
DIB fhd_dib = { FHD, IOBUS, 1, &fhdio };
|
||
|
||
UNIT fhd_unit =
|
||
{ UDATA (&fhd_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+
|
||
UNIT_MUSTBUF, FH_WDPSF) };
|
||
|
||
REG fhd_reg[] = {
|
||
{ ORDATA (CW1, fhd_cw1, 16) },
|
||
{ ORDATA (CW2, fhd_cw2, 16) },
|
||
{ ORDATA (BUF, fhd_buf, 16) },
|
||
{ FLDATA (BUSY, fhd_busy, 0) },
|
||
{ FLDATA (RDY, fhd_rdy, 0) },
|
||
{ FLDATA (DTE, fhd_dte, 0) },
|
||
{ FLDATA (ACE, fhd_ace, 0) },
|
||
{ FLDATA (EOR, fhd_eor, 0) },
|
||
{ FLDATA (DMA, fhd_dma, 0) },
|
||
{ FLDATA (CSUM, fhd_csum, 7) },
|
||
{ FLDATA (INTREQ, dev_int, INT_V_MT) },
|
||
{ FLDATA (ENABLE, dev_enb, INT_V_MT) },
|
||
{ DRDATA (TIME, fhd_time, 31), REG_NZ + PV_LEFT },
|
||
{ ORDATA (OTAS, fhd_otas, 2), REG_HRO },
|
||
{ ORDATA (CHAN, fhd_dib.chan, 5), REG_HRO },
|
||
{ FLDATA (STOP_IOE, fhd_stopioe, 0) },
|
||
{ NULL } };
|
||
|
||
MTAB fhd_mod[] = {
|
||
{ UNIT_SF, (0 << UNIT_V_SF), NULL, "1S", &fhd_set_size },
|
||
{ UNIT_SF, (1 << UNIT_V_SF), NULL, "2S", &fhd_set_size },
|
||
{ UNIT_SF, (2 << UNIT_V_SF), NULL, "3S", &fhd_set_size },
|
||
{ UNIT_SF, (3 << UNIT_V_SF), NULL, "4S", &fhd_set_size },
|
||
{ UNIT_SF, (4 << UNIT_V_SF), NULL, "5S", &fhd_set_size },
|
||
{ UNIT_SF, (5 << UNIT_V_SF), NULL, "6S", &fhd_set_size },
|
||
{ UNIT_SF, (6 << UNIT_V_SF), NULL, "7S", &fhd_set_size },
|
||
{ UNIT_SF, (7 << UNIT_V_SF), NULL, "8S", &fhd_set_size },
|
||
{ UNIT_SF, (8 << UNIT_V_SF), NULL, "9S", &fhd_set_size },
|
||
{ UNIT_SF, (9 << UNIT_V_SF), NULL, "10S", &fhd_set_size },
|
||
{ UNIT_SF, (10 << UNIT_V_SF), NULL, "11S", &fhd_set_size },
|
||
{ UNIT_SF, (11 << UNIT_V_SF), NULL, "12S", &fhd_set_size },
|
||
{ UNIT_SF, (12 << UNIT_V_SF), NULL, "13S", &fhd_set_size },
|
||
{ UNIT_SF, (13 << UNIT_V_SF), NULL, "14S", &fhd_set_size },
|
||
{ UNIT_SF, (14 << UNIT_V_SF), NULL, "15S", &fhd_set_size },
|
||
{ UNIT_SF, (15 << UNIT_V_SF), NULL, "16S", &fhd_set_size },
|
||
{ UNIT_AUTO, UNIT_AUTO, "autosize", "AUTOSIZE", NULL },
|
||
{ MTAB_XTD|MTAB_VDV, 0, NULL, "IOBUS",
|
||
&io_set_iobus, NULL, NULL },
|
||
{ MTAB_XTD|MTAB_VDV, 0, NULL, "DMC",
|
||
&io_set_dmc, NULL, NULL },
|
||
{ MTAB_XTD|MTAB_VDV, 0, NULL, "DMA",
|
||
&io_set_dma, NULL, NULL },
|
||
{ MTAB_XTD|MTAB_VDV, 0, "CHANNEL", NULL,
|
||
NULL, &io_show_chan, NULL },
|
||
{ 0 } };
|
||
|
||
DEVICE fhd_dev = {
|
||
"FHD", &fhd_unit, fhd_reg, fhd_mod,
|
||
1, 8, 22, 1, 8, 16,
|
||
NULL, NULL, &fhd_reset,
|
||
NULL, &fhd_attach, NULL,
|
||
&fhd_dib, DEV_DISABLE };
|
||
|
||
/* IO routines */
|
||
|
||
int32 fhdio (int32 inst, int32 fnc, int32 dat, int32 dev)
|
||
{
|
||
switch (inst) { /* case on opcode */
|
||
case ioOCP: /* control */
|
||
if (fnc == 04) { /* terminate output? */
|
||
fhd_eor = 1; /* stop */
|
||
CLR_INT (INT_FHD); } /* clear int req */
|
||
else if (fnc == 003) fhd_go (1); /* start, DMA */
|
||
else if (fnc == 007) fhd_go (0); /* start, IO bus */
|
||
else return IOBADFNC (dat);
|
||
break;
|
||
case ioOTA: /* output */
|
||
if (fnc) return IOBADFNC (dat); /* only fnc 0 */
|
||
if (fhd_rdy) { /* ready? */
|
||
fhd_buf = dat; /* store data */
|
||
if (fhd_otas == OTA_CW1) fhd_go1 (dat); /* expecting CW1? */
|
||
else if (fhd_otas == OTA_CW2) fhd_go2 (dat);/* expecting CW2? */
|
||
else fhd_rdy = 0; /* normal, clr ready */
|
||
return IOSKIP (dat); }
|
||
break;
|
||
case ioINA: /* input */
|
||
if (fnc) return IOBADFNC (dat); /* only fnc 0 */
|
||
if (fhd_rdy) { /* ready? */
|
||
fhd_rdy = 0; /* clear ready */
|
||
return IOSKIP (dat | fhd_buf); } /* return data */
|
||
break;
|
||
case ioSKS: /* sense */
|
||
if (((fnc == 000) && fhd_rdy) || /* 0 = skip if ready */
|
||
((fnc == 001) && !fhd_busy) || /* 1 = skip if !busy */
|
||
((fnc == 002) && !fhd_dte) || /* 2 = skip if !data err */
|
||
((fnc == 003) && !fhd_ace) || /* 3 = skip if !access err */
|
||
((fnc == 004) && !TST_INTREQ (INT_FHD))) /* 4 = skip if !interrupt */
|
||
return IOSKIP (dat);
|
||
break;
|
||
case ioEND:
|
||
fhd_eor = 1;
|
||
break; }
|
||
return dat;
|
||
}
|
||
|
||
/* Start new operation */
|
||
|
||
void fhd_go (uint32 dma)
|
||
{
|
||
int32 ch = fhd_dib.chan - 1; /* DMA/DMC chan */
|
||
|
||
if (fhd_busy) return; /* ignore if busy */
|
||
fhd_busy = 1; /* ctlr is busy */
|
||
fhd_eor = 0; /* transfer not done */
|
||
fhd_csum = 0; /* init checksum */
|
||
fhd_dte = 0; /* clear errors */
|
||
fhd_ace = 0;
|
||
if (ch >= 0) fhd_dma = dma; /* DMA allowed? */
|
||
else fhd_dma = 0; /* no, force IO bus */
|
||
fhd_otas = OTA_CW1; /* expect CW1 */
|
||
fhd_rdy = 1; /* set ready */
|
||
if (fhd_dma && Q_DMA (ch)) { /* DMA and DMA channel? */
|
||
SET_CH_REQ (ch); /* set channel request */
|
||
dma_ad[ch] = dma_ad[ch] & ~DMA_IN; } /* force output */
|
||
return;
|
||
}
|
||
|
||
/* Process command word 1 */
|
||
|
||
void fhd_go1 (uint32 dat)
|
||
{
|
||
int32 ch = fhd_dib.chan - 1; /* DMA/DMC chan */
|
||
|
||
fhd_cw1 = dat; /* store CW1 */
|
||
fhd_otas = OTA_CW2; /* expect CW2 */
|
||
fhd_rdy = 1; /* set ready */
|
||
if (fhd_dma && Q_DMA (ch)) SET_CH_REQ (ch); /* DMA? set chan request */
|
||
return;
|
||
}
|
||
|
||
/* Process command word 2 - initiate seek */
|
||
|
||
void fhd_go2 (uint32 dat)
|
||
{
|
||
int32 ch = fhd_dib.chan - 1; /* DMA/DMC chan */
|
||
uint32 sf = CW1_GETSF (fhd_cw1); /* surface */
|
||
int32 t, wa;
|
||
|
||
fhd_cw2 = dat; /* store CW2 */
|
||
fhd_otas = OTA_NOP; /* next state */
|
||
wa = CW2_GETCA (fhd_cw2) >> 1; /* word addr */
|
||
if ((wa >= FH_NUMWD) || /* if bad char addr */
|
||
((fhd_unit.flags & UNIT_ATT) == 0) || /* or unattached */
|
||
(sf >= UNIT_GETSF (fhd_unit.flags))) { /* or bad surface */
|
||
fhd_ace = 1; /* access error */
|
||
fhd_busy = 0; /* abort operation */
|
||
SET_INT (INT_FHD);
|
||
return; }
|
||
if (fhd_cw1 & CW1_RW) { /* write? */
|
||
fhd_rdy = 1; /* set ready */
|
||
if (fhd_dma) SET_CH_REQ (ch); } /* if DMA/DMC, req chan */
|
||
else { fhd_rdy = 0; /* read, clear ready */
|
||
if (fhd_dma && (ch < DMC_V_DMC1)) /* read and DMA chan? */
|
||
dma_ad[ch] = dma_ad[ch] | DMA_IN; } /* force input */
|
||
t = wa - GET_POS (fhd_time); /* delta to new loc */
|
||
if (t < 0) t = t + FH_NUMWD; /* wrap around? */
|
||
sim_activate (&fhd_unit, t * fhd_time); /* schedule op */
|
||
return;
|
||
}
|
||
|
||
/* Unit service */
|
||
|
||
t_stat fhd_svc (UNIT *uptr)
|
||
{
|
||
int32 ch = fhd_dib.chan - 1; /* DMA/DMC chan (-1 if IO bus) */
|
||
uint32 c1, c2;
|
||
|
||
if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */
|
||
fhd_ace = 1; /* access error */
|
||
fhd_busy = 0; /* abort operation */
|
||
SET_INT (INT_FHD);
|
||
return IORETURN (fhd_stopioe, SCPE_UNATT); }
|
||
|
||
if (fhd_eor || fhd_rdy) { /* done or ready set? */
|
||
if (fhd_rdy) fhd_dte = 1; /* if ready set, data err */
|
||
if (fhd_cw1 & CW1_RW) { /* write? */
|
||
if (!fhd_rdy) { /* buffer full? */
|
||
fhd_putc (uptr, fhd_buf >> 8); /* store last word */
|
||
fhd_putc (uptr, fhd_buf); }
|
||
fhd_putc (uptr, fhd_csum); } /* store csum */
|
||
else { /* read */
|
||
fhd_getc (uptr, &c1); /* get csum */
|
||
if (fhd_csum) fhd_dte = 1; } /* if csum != 0, err */
|
||
fhd_busy = 0; /* operation complete */
|
||
SET_INT (INT_FHD);
|
||
return SCPE_OK; }
|
||
|
||
if (fhd_cw1 & CW1_RW) { /* write? */
|
||
if (fhd_putc (uptr, fhd_buf >> 8)) return SCPE_OK;
|
||
if (fhd_putc (uptr, fhd_buf)) return SCPE_OK; }
|
||
else { if (fhd_getc (uptr, &c1)) return SCPE_OK; /* read */
|
||
if (fhd_getc (uptr, &c2)) return SCPE_OK;
|
||
fhd_buf = (c1 << 8) | c2; }
|
||
sim_activate (uptr, fhd_time); /* next word */
|
||
fhd_rdy = 1; /* set ready */
|
||
if (fhd_dma) SET_CH_REQ (ch); /* if DMA/DMC, req chan */
|
||
return SCPE_OK;
|
||
}
|
||
|
||
/* Read character from disk */
|
||
|
||
t_bool fhd_getc (UNIT *uptr, uint32 *ch)
|
||
{
|
||
uint32 sf = CW1_GETSF (fhd_cw1); /* surface */
|
||
uint32 tk = CW1_GETTK (fhd_cw1); /* track */
|
||
uint32 ca = CW2_GETCA (fhd_cw2); /* char addr */
|
||
uint32 wa = ca >> 1; /* word addr */
|
||
uint32 ba = (((sf * FH_NUMTK) + tk) * FH_NUMWD) + wa; /* buffer offset */
|
||
uint16 *fbuf = uptr->filebuf; /* buffer base */
|
||
uint32 wd;
|
||
|
||
if (fhd_bad_wa (wa)) return TRUE; /* addr bad? */
|
||
fhd_cw2 = fhd_cw2 + 1; /* incr char addr */
|
||
if (ca & 1) wd = fbuf[ba] & 0377; /* select char */
|
||
else wd = (fbuf[ba] >> 8) & 0377;
|
||
fhd_csum = fhd_csword (fhd_csum, wd); /* put in csum */
|
||
*ch = wd; /* return */
|
||
return FALSE;
|
||
}
|
||
|
||
/* Write character to disk */
|
||
|
||
t_bool fhd_putc (UNIT *uptr, uint32 ch)
|
||
{
|
||
uint32 sf = CW1_GETSF (fhd_cw1); /* surface */
|
||
uint32 tk = CW1_GETTK (fhd_cw1); /* track */
|
||
uint32 ca = CW2_GETCA (fhd_cw2); /* char addr */
|
||
uint32 wa = ca >> 1; /* word addr */
|
||
uint32 ba = (((sf * FH_NUMTK) + tk) * FH_NUMWD) + wa; /* buffer offset */
|
||
uint16 *fbuf = uptr->filebuf; /* buffer base */
|
||
|
||
ch = ch & 0377; /* mask char */
|
||
if (fhd_bad_wa (wa)) return TRUE; /* addr bad? */
|
||
fhd_cw2 = fhd_cw2 + 1; /* incr char addr */
|
||
if (ca & 1) fbuf[ba] = (fbuf[ba] & ~0377) | ch; /* odd? low char */
|
||
else fbuf[ba] = (fbuf[ba] & 0377) | (ch << 8); /* even, hi char */
|
||
fhd_csum = fhd_csword (fhd_csum, ch); /* put in csum */
|
||
if (ba >= uptr->hwmark) uptr->hwmark = ba + 1; /* update hwmark */
|
||
return FALSE;
|
||
}
|
||
|
||
/* Check word address */
|
||
|
||
t_bool fhd_bad_wa (uint32 wa)
|
||
{
|
||
if (wa >= FH_NUMWD) { /* bad address? */
|
||
fhd_ace = 1; /* access error */
|
||
fhd_busy = 0; /* abort operation */
|
||
SET_INT (INT_FHD);
|
||
return TRUE; }
|
||
return FALSE;
|
||
}
|
||
|
||
/* Add character to checksum (parity) */
|
||
|
||
uint32 fhd_csword (uint32 cs, uint32 ch)
|
||
{
|
||
while (ch) { /* count bits */
|
||
ch = ch & ~(ch & (-(int32) ch));
|
||
cs = cs ^ 0200; } /* invert cs for each 1 */
|
||
return cs;
|
||
}
|
||
|
||
/* Reset routine */
|
||
|
||
t_stat fhd_reset (DEVICE *dptr)
|
||
{
|
||
fhd_busy = 0; /* reset state */
|
||
fhd_rdy = 0;
|
||
fhd_ace = 0;
|
||
fhd_dte = 0;
|
||
fhd_eor = 0;
|
||
fhd_otas = OTA_NOP;
|
||
fhd_cw1 = fhd_cw2 = fhd_buf = 0;
|
||
CLR_INT (INT_FHD); /* clear int, enb */
|
||
CLR_ENB (INT_FHD);
|
||
sim_cancel (&fhd_unit); /* cancel operation */
|
||
return SCPE_OK;
|
||
}
|
||
|
||
/* Attach routine */
|
||
|
||
t_stat fhd_attach (UNIT *uptr, char *cptr)
|
||
{
|
||
uint32 sz, sf;
|
||
uint32 ds_bytes = FH_WDPSF * sizeof (int16);
|
||
|
||
if ((uptr->flags & UNIT_AUTO) && (sz = sim_fsize (cptr))) {
|
||
sf = (sz + ds_bytes - 1) / ds_bytes;
|
||
if (sf >= FH_NUMSF) sf = FH_NUMSF - 1;
|
||
uptr->flags = (uptr->flags & ~UNIT_SF) |
|
||
(sf << UNIT_V_SF); }
|
||
uptr->capac = UNIT_GETSF (uptr->flags) * FH_WDPSF;
|
||
return attach_unit (uptr, cptr);
|
||
}
|
||
|
||
/* Set size routine */
|
||
|
||
t_stat fhd_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
|
||
{
|
||
if (val < 0) return SCPE_IERR;
|
||
if (uptr->flags & UNIT_ATT) return SCPE_ALATT;
|
||
uptr->capac = UNIT_GETSF (val) * FH_WDPSF;
|
||
return SCPE_OK;
|
||
}
|