969 lines
39 KiB
C
969 lines
39 KiB
C
/*
|
||
* BESM-6 magnetic disk device
|
||
*
|
||
* Copyright (c) 2009, Serge Vakulenko
|
||
* Copyright (c) 2009, Leonid Broukhis
|
||
*
|
||
* 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
|
||
* SERGE VAKULENKO OR LEONID BROUKHIS 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 Leonid Broukhis or
|
||
* Serge Vakulenko shall not be used in advertising or otherwise to promote
|
||
* the sale, use or other dealings in this Software without prior written
|
||
* authorization from Leonid Broukhis and Serge Vakulenko.
|
||
*/
|
||
#include "besm6_defs.h"
|
||
#include <ctype.h>
|
||
#include <sys/types.h>
|
||
#include <sys/stat.h>
|
||
|
||
/*
|
||
* Управляющее слово обмена с магнитным диском.
|
||
*/
|
||
#define DISK_BLOCK 0740000000 /* номер блока памяти - 27-24 рр */
|
||
#define DISK_READ_SYSDATA 004000000 /* считывание только служебных слов */
|
||
#define DISK_PAGE_MODE 001000000 /* обмен целой страницей */
|
||
#define DISK_READ 000400000 /* чтение с диска в память */
|
||
#define DISK_PAGE 000370000 /* номер страницы памяти */
|
||
#define DISK_HALFPAGE 000004000 /* выбор половины листа */
|
||
#define DISK_UNIT 000001600 /* номер устройства */
|
||
#define DISK_HALFZONE 000000001 /* выбор половины зоны */
|
||
|
||
/*
|
||
* Status register bits (most are unused: error conditions are not simulated)
|
||
*/
|
||
#define STATUS_SEEK 000000377 /* "Seek done" mask, per unit */
|
||
#define STATUS_READY 000000400 /* Selected unit is ready */
|
||
#define STATUS_SEEK_FAIL 000001000 /* Head location unknown, unit not ready */
|
||
#define STATUS_CHECKSUM 000002000 /* Bad checksum on read */
|
||
#define STATUS_FAILURE 000004000 /* Failure, OR of some upper bits */
|
||
#define STATUS_MAYDAY 000010000 /* Unspecified failure */
|
||
#define STATUS_NO_AMRK 000020000 /* Address marker not found after a revolution */
|
||
#define STATUS_WRONG_CYL 000040000 /* Wrong address marker */
|
||
#define STATUS_WRONG_ID 000100000 /* Bad track ID */
|
||
#define STATUS_BAD_ACSUM 000200000 /* Bad checksum of the address marker */
|
||
#define STATUS_UNFINISHED 000400000 /* IO not finished after a revolution */
|
||
#define STATUS_TRK_PARITY 001000000 /* Track parity in two-track IO */
|
||
#define STATUS_READONLY 002000000 /* The selected unit is read-only */
|
||
#define STATUS_POWERUP 004000000 /* The unit is powered up */
|
||
#define STATUS_ABSENT 010000000 /* The unit is not connected */
|
||
#define STATUS_BUF_ERR 020000000 /* Transfer buffer not ready */
|
||
|
||
/*
|
||
* Total size of a "7.25 Mb" disk is 1000 (decimal) blocks;
|
||
* of a "29 Mb" disk - 4000 blocks, out of which 4 are so called
|
||
* pre-blocks. Logical blocks are mapped to physical by adding 4.
|
||
* Physical blocks 0 to 2 are accesible only by standalone programs,
|
||
* block 3 has the logical number "minus one".
|
||
*/
|
||
#define SYSTEM_VOLUME_ID 2053
|
||
/*
|
||
* Параметры обмена с внешним устройством.
|
||
*/
|
||
typedef struct {
|
||
int op; /* Условное слово обмена */
|
||
int group; /* Unit group number */
|
||
int dev; /* Номер устройства, 0..7 */
|
||
int zone; /* Номер зоны на диске */
|
||
int track; /* Выбор половины зоны на диске */
|
||
int memory; /* Начальный адрес памяти */
|
||
int format; /* Флаг разметки */
|
||
int status; /* Регистр состояния */
|
||
t_value mask_grp; /* Маска готовности для ГРП */
|
||
int mask_fail; /* Маска ошибки обмена */
|
||
t_value *sysdata; /* Буфер системных данных */
|
||
} KMD;
|
||
|
||
static KMD controller [2]; /* Две стойки КМД */
|
||
int disk_fail; /* Маска ошибок по направлениям */
|
||
|
||
t_stat disk_event (UNIT *u);
|
||
|
||
/*
|
||
* DISK data structures
|
||
*
|
||
* md_dev DISK device descriptor
|
||
* md_unit DISK unit descriptor
|
||
* md_reg DISK register list
|
||
*/
|
||
UNIT md_unit [64] = {
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
|
||
};
|
||
|
||
REG disk_reg[] = {
|
||
{ ORDATA (КУС_0, controller[0].op, 24) },
|
||
{ ORDATA (ЛИНЕЙКА_0, controller[0].group, 2) },
|
||
{ ORDATA (УСТР_0, controller[0].dev, 3) },
|
||
{ ORDATA (ЗОНА_0, controller[0].zone, 10) },
|
||
{ ORDATA (ДОРОЖКА_0, controller[0].track, 2) },
|
||
{ ORDATA (МОЗУ_0, controller[0].memory, 20) },
|
||
{ ORDATA (РС_0, controller[0].status, 24) },
|
||
{ 0 },
|
||
{ ORDATA (КУС_1, controller[1].op, 24) },
|
||
{ ORDATA (ЛИНЕЙКА_1, controller[1].group, 2) },
|
||
{ ORDATA (УСТР_1, controller[1].dev, 3) },
|
||
{ ORDATA (ЗОНА_1, controller[1].zone, 10) },
|
||
{ ORDATA (ДОРОЖКА_1, controller[1].track, 2) },
|
||
{ ORDATA (МОЗУ_1, controller[1].memory, 20) },
|
||
{ ORDATA (РС_1, controller[1].status, 24) },
|
||
{ ORDATA (ОШ, disk_fail, 6) },
|
||
{ 0 }
|
||
};
|
||
|
||
static FILE * syslog = NULL;
|
||
t_stat disk_setsyslog (UNIT *up, int32 v, CONST char *cp, void *dp) {
|
||
if (syslog) {
|
||
fclose(syslog);
|
||
syslog = NULL;
|
||
}
|
||
if (strcasecmp(cp, "OFF") == 0)
|
||
return SCPE_OK;
|
||
syslog = fopen(cp, "a");
|
||
if (!syslog)
|
||
return sim_messagef (SCPE_OPENERR, "Failed to open SYSLOG file %s: %s\n", cp, strerror(errno));
|
||
return SCPE_OK;
|
||
}
|
||
|
||
#define DISK_TYPE_MASK (1 << UNIT_V_UF)
|
||
#define DISK_TYPE_7_25M 0
|
||
#define DISK_TYPE_29M (1 << UNIT_V_UF)
|
||
#define IS_29MB(u) (((u)->flags & DISK_TYPE_MASK) == DISK_TYPE_29M)
|
||
|
||
t_stat disk_set_type (UNIT *up, int32 v, CONST char *cp, void *dp) {
|
||
int first_unit = (up->dptr - md_dev) * 8;
|
||
int unit;
|
||
for (unit = first_unit; unit < first_unit + 8; ++unit) {
|
||
if (md_unit[unit].flags & UNIT_ATT)
|
||
return sim_messagef(SCPE_ALATT, "Drive type cannot be set if any unit is attached");
|
||
}
|
||
for (unit = first_unit; unit < first_unit + 8; ++unit) {
|
||
md_unit[unit].flags &= ~DISK_TYPE_MASK;
|
||
md_unit[unit].flags |= v;
|
||
md_unit[unit].capac = 7250000 * (v ? 4 : 1);
|
||
}
|
||
return SCPE_OK;
|
||
}
|
||
|
||
t_stat disk_show_type (FILE *f, UNIT *up, int32 v, CONST void *dp) {
|
||
fprintf(f, IS_29MB(up) ? "EC-5061" : "EC-5052");
|
||
return SCPE_OK;
|
||
}
|
||
|
||
|
||
MTAB disk_mod[] = {
|
||
{ MTAB_VDV, DISK_TYPE_7_25M, "", "EC-5052", &disk_set_type, &disk_show_type, NULL,
|
||
"EC-5052 drive (7.25 Mb)"},
|
||
{ MTAB_VDV, DISK_TYPE_29M, NULL, "EC-5061", &disk_set_type, NULL, NULL, "EC-5061 drive (29 Mb)"},
|
||
{ MTAB_XTD | MTAB_VDV | MTAB_VALR, 1, NULL,
|
||
"SYSLOG", &disk_setsyslog, NULL, NULL, "file name (always appending) or OFF" },
|
||
{ 0 }
|
||
};
|
||
|
||
|
||
t_stat disk_reset (DEVICE *dptr);
|
||
t_stat disk_attach (UNIT *uptr, CONST char *cptr);
|
||
t_stat disk_detach (UNIT *uptr);
|
||
|
||
#define DEB_OPS 000001
|
||
#define DEB_RRD 000002
|
||
#define DEB_RWR 000004
|
||
#define DEB_INT 000010
|
||
#define DEB_TRC 000020
|
||
#define DEB_DAT 000040
|
||
#define DEB_STA 000100
|
||
|
||
DEBTAB disk_deb[] = {
|
||
{ "OPS", DEB_OPS, "transactions" },
|
||
{ "RRD", DEB_RRD, "register reads" },
|
||
{ "RWR", DEB_RWR, "register writes" },
|
||
{ "INTERRUPT", DEB_INT, "interrupts" },
|
||
{ "TRACE", DEB_TRC, "trace" },
|
||
{ "DATA", DEB_DAT, "transfer data" },
|
||
{ "STATUS", DEB_STA, "status check" },
|
||
{ NULL, 0 }
|
||
};
|
||
|
||
DEVICE md_dev[8] = {
|
||
{
|
||
"MD0", md_unit, disk_reg, disk_mod,
|
||
8, 8, 21, 50, 8, 50,
|
||
NULL, NULL, &disk_reset, NULL, &disk_attach, &disk_detach,
|
||
NULL, DEV_DISABLE | DEV_DEBUG, 0, disk_deb
|
||
},
|
||
{
|
||
"MD1", md_unit + 8, disk_reg, disk_mod,
|
||
8, 8, 21, 50, 8, 50,
|
||
NULL, NULL, &disk_reset, NULL, &disk_attach, &disk_detach,
|
||
NULL, DEV_DISABLE | DEV_DEBUG, 0, disk_deb
|
||
},
|
||
{
|
||
"MD2", md_unit + 16, disk_reg, disk_mod,
|
||
8, 8, 21, 50, 8, 50,
|
||
NULL, NULL, &disk_reset, NULL, &disk_attach, &disk_detach,
|
||
NULL, DEV_DISABLE | DEV_DEBUG, 0, disk_deb
|
||
},
|
||
{
|
||
"MD3", md_unit + 24, disk_reg, disk_mod,
|
||
8, 8, 21, 50, 8, 50,
|
||
NULL, NULL, &disk_reset, NULL, &disk_attach, &disk_detach,
|
||
NULL, DEV_DISABLE | DEV_DEBUG, 0, disk_deb
|
||
},
|
||
{
|
||
"MD4", md_unit + 32, disk_reg + 8, disk_mod,
|
||
8, 8, 21, 50, 8, 50,
|
||
NULL, NULL, &disk_reset, NULL, &disk_attach, &disk_detach,
|
||
NULL, DEV_DISABLE | DEV_DEBUG, 0, disk_deb
|
||
},
|
||
{
|
||
"MD5", md_unit + 40, disk_reg + 8, disk_mod,
|
||
8, 8, 21, 50, 8, 50,
|
||
NULL, NULL, &disk_reset, NULL, &disk_attach, &disk_detach,
|
||
NULL, DEV_DISABLE | DEV_DEBUG, 0, disk_deb
|
||
},
|
||
{
|
||
"MD6", md_unit + 48, disk_reg + 8, disk_mod,
|
||
8, 8, 21, 50, 8, 50,
|
||
NULL, NULL, &disk_reset, NULL, &disk_attach, &disk_detach,
|
||
NULL, DEV_DISABLE | DEV_DEBUG, 0, disk_deb
|
||
},
|
||
{
|
||
"MD7", md_unit + 56, disk_reg + 8, disk_mod,
|
||
8, 8, 21, 50, 8, 50,
|
||
NULL, NULL, &disk_reset, NULL, &disk_attach, &disk_detach,
|
||
NULL, DEV_DISABLE | DEV_DEBUG, 0, disk_deb
|
||
},
|
||
};
|
||
|
||
/*
|
||
* Определение контроллера по устройству.
|
||
*/
|
||
static KMD *unit_to_ctlr (UNIT *u)
|
||
{
|
||
return &controller[(u - md_unit) / 32];
|
||
}
|
||
|
||
/*
|
||
* Reset routine
|
||
*/
|
||
t_stat disk_reset (DEVICE *dptr)
|
||
{
|
||
int i;
|
||
int ctlr = (dptr - md_dev) / 4;
|
||
int first_unit = (dptr - md_dev) * 8;
|
||
KMD *c = &controller[ctlr];
|
||
memset (c, 0, sizeof (KMD));
|
||
c->sysdata = &memory [030 + ctlr * 8];
|
||
c->mask_grp = GRP_CHAN3_FREE >> ctlr;
|
||
c->mask_fail = 020 >> ctlr;
|
||
for (i = first_unit; i < first_unit + 8; ++i) {
|
||
md_unit[i].dptr = dptr;
|
||
md_unit[i].capac = 7250000 * (IS_29MB(&md_unit[i]) ? 4 : 1);
|
||
sim_cancel (&md_unit[i]);
|
||
}
|
||
return SCPE_OK;
|
||
}
|
||
|
||
t_stat disk_attach (UNIT *u, CONST char *cptr)
|
||
{
|
||
t_stat s;
|
||
int32 saved_switches = sim_switches;
|
||
sim_switches |= SWMASK ('E');
|
||
|
||
while (1) {
|
||
s = attach_unit (u, cptr);
|
||
if ((s == SCPE_OK) && (sim_switches & SWMASK ('N'))) {
|
||
t_value control[4]; /* block (zone) number, key, userid, checksum */
|
||
int diskno, blkno, word;
|
||
char *filenamepart = NULL;
|
||
const char *pos;
|
||
/* Using the rightmost sequence of digits within the filename
|
||
* provided in the command line as a volume number,
|
||
* e.g. "/var/tmp/besm6/2052.bin" -> 2052
|
||
*/
|
||
filenamepart = sim_filepath_parts (u->filename, "n");
|
||
pos = filenamepart + strlen(filenamepart);
|
||
while (pos > filenamepart && !isdigit(*--pos));
|
||
while (pos > filenamepart && isdigit(*pos)) --pos;
|
||
if (!isdigit(*pos)) ++pos;
|
||
diskno = strtoul (pos, NULL, 10);
|
||
free (filenamepart);
|
||
if (diskno < 2048 || diskno > 4095) {
|
||
if (diskno == 0)
|
||
s = sim_messagef (SCPE_ARG,
|
||
"%s: filename must contain volume number 2048..4095\n",
|
||
sim_uname(u));
|
||
else
|
||
s = sim_messagef (SCPE_ARG,
|
||
"%s: disk volume %d from filename %s invalid (must be 2048..4095)\n",
|
||
sim_uname (u), diskno, cptr);
|
||
filenamepart = strdup (u->filename);
|
||
detach_unit (u);
|
||
remove (filenamepart);
|
||
free (filenamepart);
|
||
return s; /* not formatting */
|
||
}
|
||
sim_messagef (SCPE_OK, "%s: formatting disk volume %d\n", sim_uname (u), diskno);
|
||
|
||
control[1] = SET_PARITY(0, PARITY_NUMBER);
|
||
control[2] = SET_PARITY(0, PARITY_NUMBER);
|
||
control[3] = SET_PARITY(0, PARITY_NUMBER);
|
||
|
||
control[1] |= 01370707LL << 24; /* Magic mark */
|
||
control[1] |= diskno << 12;
|
||
|
||
/* Unlike the O/S routine, does not format the (useless) reserve tracks */
|
||
for (blkno = 0; blkno < (IS_29MB(u) ? 4000 : 1000); ++blkno) {
|
||
uint32 val = IS_29MB(u) ? blkno : 2 * blkno;
|
||
control[0] = SET_PARITY((t_value)val << 36, PARITY_NUMBER);
|
||
sim_fwrite(control, sizeof(t_value), 4, u->fileref);
|
||
control[0] = SET_PARITY((t_value)(val+1) << 36, PARITY_NUMBER);
|
||
sim_fwrite(control, sizeof(t_value), 4, u->fileref);
|
||
for (word = 0; word < 02000; ++word) {
|
||
sim_fwrite(control+2, sizeof(t_value), 1, u->fileref);
|
||
}
|
||
}
|
||
}
|
||
if (s == SCPE_OK ||
|
||
(saved_switches & SWMASK ('E')) ||
|
||
(sim_switches & SWMASK('N')))
|
||
break;
|
||
sim_switches |= SWMASK ('N');
|
||
}
|
||
return SCPE_OK;
|
||
}
|
||
|
||
t_stat disk_detach (UNIT *u)
|
||
{
|
||
/* TODO: сброс бита ГРП готовности направления при отключении последнего диска. */
|
||
return detach_unit (u);
|
||
}
|
||
|
||
t_value spread (t_value val)
|
||
{
|
||
int i, j;
|
||
t_value res = 0;
|
||
|
||
for (i = 0; i < 5; i++)
|
||
for (j = 0; j < 9; j++)
|
||
if (val & (1LL<<(i+j*5)))
|
||
res |= 1LL << (i*9+j);
|
||
return res & BITS48;
|
||
}
|
||
|
||
/*
|
||
* Отладочная печать массива данных обмена.
|
||
*/
|
||
static void log_data (t_value *data, int nwords)
|
||
{
|
||
int i;
|
||
t_value val;
|
||
|
||
for (i=0; i<nwords; ++i) {
|
||
val = data[i];
|
||
fprintf (sim_log, " %04o-%04o-%04o-%04o",
|
||
(int) (val >> 36) & 07777,
|
||
(int) (val >> 24) & 07777,
|
||
(int) (val >> 12) & 07777,
|
||
(int) val & 07777);
|
||
if ((i & 3) == 3)
|
||
fprintf (sim_log, "\n");
|
||
}
|
||
if ((i & 3) != 0)
|
||
fprintf (sim_log, "\n");
|
||
}
|
||
|
||
/*
|
||
* Сложение с переносом вправо.
|
||
*/
|
||
static unsigned sum_with_right_carry (unsigned a, unsigned b)
|
||
{
|
||
unsigned c;
|
||
|
||
while (b) {
|
||
c = a & b;
|
||
a ^= b;
|
||
b = c >> 1;
|
||
}
|
||
return a;
|
||
}
|
||
|
||
/*
|
||
* Запись на диск.
|
||
*/
|
||
void disk_write (UNIT *u)
|
||
{
|
||
KMD *c = unit_to_ctlr (u);
|
||
int cnum = c - controller;
|
||
if (u->dptr->dctrl & DEB_DAT)
|
||
besm6_debug ("::: запись МД %02o зона %04o память %05o-%05o",
|
||
c->dev, c->zone, c->memory, c->memory + 1023);
|
||
if (fseek (u->fileref, ZONE_SIZE * c->zone * 8, SEEK_SET) == 0) {
|
||
sim_fwrite (c->sysdata, 8, 8, u->fileref);
|
||
sim_fwrite (&memory [c->memory], 8, 1024, u->fileref);
|
||
}
|
||
|
||
/* Logging system disk accesses */
|
||
if (syslog && ((c->sysdata[1] >> 12) & 0xFFF) == SYSTEM_VOLUME_ID) {
|
||
fprintf(syslog, "W %04o @%05o\n", (c->zone-4)&07777, c->memory);
|
||
fflush(syslog);
|
||
}
|
||
|
||
if (ferror (u->fileref))
|
||
longjmp (cpu_halt, SCPE_IOERR);
|
||
}
|
||
|
||
void disk_write_track (UNIT *u)
|
||
{
|
||
KMD *c = unit_to_ctlr (u);
|
||
int cnum = c - controller;
|
||
if (u->dptr->dctrl & DEB_DAT)
|
||
besm6_debug ("::: запись МД %02o полузона %04o.%d память %05o-%05o",
|
||
c->dev, c->zone, c->track, c->memory, c->memory + 511);
|
||
if (fseek (u->fileref, (ZONE_SIZE*c->zone + 4*c->track) * 8,
|
||
SEEK_SET) == 0) {
|
||
sim_fwrite (c->sysdata + 4*c->track, 8, 4, u->fileref);
|
||
if (fseek (u->fileref, (8 + ZONE_SIZE*c->zone + 512*c->track) * 8,
|
||
SEEK_SET) == 0) {
|
||
sim_fwrite (&memory [c->memory], 8, 512, u->fileref);
|
||
}
|
||
}
|
||
if (ferror (u->fileref))
|
||
longjmp (cpu_halt, SCPE_IOERR);
|
||
}
|
||
|
||
/*
|
||
* Форматирование дорожки.
|
||
*/
|
||
void disk_format (UNIT *u)
|
||
{
|
||
KMD *c = unit_to_ctlr (u);
|
||
t_value fmtbuf[5];
|
||
t_value *ptr;
|
||
int i;
|
||
int cnum = c - controller;
|
||
/* По сути, эмулятору ничего делать не надо. */
|
||
if (! (u->dptr->dctrl & DEB_DAT))
|
||
return;
|
||
|
||
/* Находим начало записываемого заголовка. */
|
||
ptr = &memory [c->memory];
|
||
while ((*ptr & BITS48) == 0)
|
||
ptr++;
|
||
|
||
/* Декодируем из гребенки в нормальный вид. */
|
||
for (i = 0; i < 5; i++)
|
||
fmtbuf[i] = spread (ptr[i]);
|
||
|
||
/* При первой попытке разметки адресный маркер начинается в старшем 5-разрядном слоге,
|
||
* пропускаем первый слог. */
|
||
for (i=0; i<5; i++)
|
||
fmtbuf[i] = ((fmtbuf[i] & BITS48) << 5) |
|
||
(i == 4 ? 0 : (fmtbuf[i+1] >> 40) & BITS(5));
|
||
|
||
log_data(fmtbuf, 5);
|
||
|
||
/* Печатаем идентификатор, адрес и контрольную сумму адреса. */
|
||
if (u->dptr->dctrl & DEB_TRC) {
|
||
if (IS_29MB(u))
|
||
besm6_debug ("::: формат МД %02o зона %04o память %05o skip %02o и-а-кса %010o %010o",
|
||
c->dev, c->zone, c->memory, ptr - memory -c ->memory,
|
||
(int) (fmtbuf[0] >> 8 & BITS(30)),
|
||
(int) (fmtbuf[2] >> 14 & BITS(30)));
|
||
else
|
||
besm6_debug ("::: формат МД %02o полузона %04o.%d память %05o skip %02o и-а-кса %010o %010o",
|
||
c->dev, c->zone, c->track, c->memory, (uint32) (ptr - memory -c ->memory),
|
||
(int) (fmtbuf[0] >> 8 & BITS(30)),
|
||
(int) (fmtbuf[2] >> 14 & BITS(30)));
|
||
}
|
||
}
|
||
|
||
/*
|
||
* Чтение с диска.
|
||
*/
|
||
void disk_read (UNIT *u)
|
||
{
|
||
KMD *c = unit_to_ctlr (u);
|
||
int cnum = c - controller;
|
||
if (u->dptr->dctrl & DEB_DAT)
|
||
besm6_debug ((c->op & DISK_READ_SYSDATA) ?
|
||
"::: чтение МД %02o зона %04o служебные слова" :
|
||
"::: чтение МД %02o зона %04o память %05o-%05o",
|
||
c->dev, c->zone, c->memory, c->memory + 1023);
|
||
if (fseek (u->fileref, ZONE_SIZE * c->zone * 8, SEEK_SET) != 0 ||
|
||
sim_fread (c->sysdata, 8, 8, u->fileref) != 8) {
|
||
/* Чтение неинициализированного диска */
|
||
disk_fail |= c->mask_fail;
|
||
return;
|
||
}
|
||
if (! (c->op & DISK_READ_SYSDATA) &&
|
||
sim_fread (&memory [c->memory], 8, 1024, u->fileref) != 1024) {
|
||
/* Чтение неинициализированного диска */
|
||
disk_fail |= c->mask_fail;
|
||
return;
|
||
}
|
||
|
||
/* Logging system disk accesses */
|
||
if (syslog && ((c->sysdata[1] >> 12) & 0xFFF) == SYSTEM_VOLUME_ID) {
|
||
fprintf(syslog, "R %04o @%05o\n", (c->zone-4)&07777, c->memory);
|
||
fflush(syslog);
|
||
}
|
||
|
||
if (ferror (u->fileref))
|
||
longjmp (cpu_halt, SCPE_IOERR);
|
||
}
|
||
|
||
t_value collect (t_value val)
|
||
{
|
||
int i, j;
|
||
t_value res = 0;
|
||
|
||
for (i = 0; i < 5; i++)
|
||
for (j = 0; j < 9; j++)
|
||
if (val & (1LL<<(i*9+j)))
|
||
res |= 1LL << (i+j*5);
|
||
return res & BITS48;
|
||
}
|
||
|
||
void disk_read_track (UNIT *u)
|
||
{
|
||
KMD *c = unit_to_ctlr (u);
|
||
int cnum = c - controller;
|
||
if (u->dptr->dctrl & DEB_DAT)
|
||
besm6_debug ((c->op & DISK_READ_SYSDATA) ?
|
||
"::: чтение МД %02o полузона %04o.%d служебные слова" :
|
||
"::: чтение МД %02o полузона %04o.%d память %05o-%05o",
|
||
c->dev, c->zone, c->track, c->memory, c->memory + 511);
|
||
if (fseek (u->fileref, (ZONE_SIZE*c->zone + 4*c->track) * 8, SEEK_SET) != 0 ||
|
||
sim_fread (c->sysdata + 4*c->track, 8, 4, u->fileref) != 4) {
|
||
/* Чтение неинициализированного диска */
|
||
disk_fail |= c->mask_fail;
|
||
return;
|
||
}
|
||
if (! (c->op & DISK_READ_SYSDATA)) {
|
||
if (fseek (u->fileref, (8 + ZONE_SIZE*c->zone + 512*c->track) * 8,
|
||
SEEK_SET) != 0 ||
|
||
sim_fread (&memory [c->memory], 8, 512, u->fileref) != 512) {
|
||
/* Чтение неинициализированного диска */
|
||
disk_fail |= c->mask_fail;
|
||
return;
|
||
}
|
||
}
|
||
if (ferror (u->fileref))
|
||
longjmp (cpu_halt, SCPE_IOERR);
|
||
}
|
||
|
||
/*
|
||
* Чтение заголовка дорожки.
|
||
*/
|
||
void disk_read_header (UNIT *u)
|
||
{
|
||
KMD *c = unit_to_ctlr (u);
|
||
t_value *sysdata = IS_29MB(u) ? c->sysdata : c->sysdata + 4*c->track;
|
||
int iaksa, i, cyl, head;
|
||
int reserve_start = IS_29MB(u) ? 07640 : 01750;
|
||
|
||
/* Адрес: номер цилиндра и головки. */
|
||
if (IS_29MB(u)) {
|
||
head = c->zone;
|
||
cyl = head / 20;
|
||
head %= 20;
|
||
iaksa = (head << 3) + (cyl << 8);
|
||
iaksa <<= 12;
|
||
} else {
|
||
head = (c->zone << 1) + c->track;
|
||
cyl = head / 10;
|
||
head %= 10;
|
||
iaksa = (cyl << 20) | (head << 16);
|
||
}
|
||
|
||
/* Идентификатор дорожки замены. */
|
||
if (c->zone >= reserve_start)
|
||
iaksa |= BBIT(30);
|
||
|
||
/* Контрольная сумма адреса с переносом вправо. */
|
||
iaksa |= BITS(12) & ~sum_with_right_carry (iaksa >> 12, iaksa >> 24);
|
||
|
||
/* Амиакса, 42 нуля, амиакса, много единиц. */
|
||
sysdata[0] = 07404000000000000LL | (t_value) iaksa << 8;
|
||
sysdata[1] = 03740LL;
|
||
sysdata[2] = 00400000000037777LL | (t_value) iaksa << 14;
|
||
sysdata[3] = BITS48;
|
||
|
||
if (IS_29MB(u)) {
|
||
for (i=0; i<4; i++) {
|
||
memory[c->memory + i + 014] = SET_PARITY(sysdata[i] & 0777777777777777LL, PARITY_NUMBER);
|
||
}
|
||
}
|
||
|
||
/* Кодируем гребенку. */
|
||
for (i=0; i<4; i++)
|
||
sysdata[i] = SET_PARITY (collect (sysdata[i]), PARITY_NUMBER);
|
||
|
||
}
|
||
|
||
/*
|
||
* Задание адреса памяти и длины массива для последующего обращения к диску.
|
||
* Номера дисковода и дорожки будут выданы позже, командой 033 0023(0024).
|
||
*/
|
||
void disk_io (int ctlr, uint32 cmd)
|
||
{
|
||
KMD *c = &controller [ctlr];
|
||
int cnum = c - controller;
|
||
uint32 rem = cmd & ~(DISK_PAGE_MODE | DISK_PAGE | DISK_BLOCK | DISK_READ | DISK_READ_SYSDATA);
|
||
if (rem && md_dev[ctlr * 4].dctrl & DEB_RWR) {
|
||
besm6_debug ("::: КМД %c: unknown bits in IO request %08o", ctlr + '3', rem);
|
||
}
|
||
c->op = cmd;
|
||
c->format = 0;
|
||
if (c->op & DISK_PAGE_MODE) {
|
||
/* Обмен страницей */
|
||
c->memory = (cmd & DISK_PAGE) >> 2 | (cmd & DISK_BLOCK) >> 8;
|
||
} else {
|
||
/* Обмен половиной страницы (дорожкой) */
|
||
c->memory = (cmd & (DISK_PAGE | DISK_HALFPAGE)) >> 2 | (cmd & DISK_BLOCK) >> 8;
|
||
}
|
||
if (md_dev[ctlr * 4].dctrl & DEB_RWR)
|
||
besm6_debug ("::: КМД %c: задание на %s %08o RAM @%05o", ctlr + '3',
|
||
(c->op & DISK_READ) ? "чтение" : "запись", cmd, c->memory);
|
||
disk_fail &= ~c->mask_fail;
|
||
|
||
/* Гасим главный регистр прерываний. */
|
||
GRP &= ~c->mask_grp;
|
||
}
|
||
|
||
/*
|
||
* Управление диском: команда 00 033 0023(0024).
|
||
*/
|
||
void disk_ctl (int ctlr, uint32 cmd)
|
||
{
|
||
KMD *c = &controller [ctlr];
|
||
UNIT *u = c->dev < 0 ? &md_unit[0] : &md_unit [c->dev];
|
||
|
||
if ((md_dev[ctlr].dctrl & DEB_OPS || (c->dev != -1 && u->dptr->dctrl & DEB_OPS)) && cmd & BBIT(13)) {
|
||
besm6_debug ("::: КМД %c: bit 13 + %04o",
|
||
ctlr + '3', cmd & 07777);
|
||
}
|
||
|
||
if (cmd & BBIT(12)) {
|
||
if (c->dev == -1)
|
||
besm6_debug("Setting block address for unknown device");
|
||
|
||
/* Выдача в КМД адреса дорожки.
|
||
* Здесь же выполняем обмен с диском.
|
||
* Номер дисковода к этому моменту уже известен. */
|
||
if ((u->dptr->flags & DEV_DIS) || ! (u->flags & UNIT_ATT)) {
|
||
/* Device not attached. */
|
||
disk_fail |= c->mask_fail;
|
||
return;
|
||
}
|
||
if (IS_29MB(u)) {
|
||
c->zone = ((cmd & BITS(11)) << 1) | (c->zone & 1);
|
||
} else {
|
||
c->zone = (cmd >> 1) & BITS(10);
|
||
c->track = cmd & 1;
|
||
}
|
||
|
||
if (u->dptr->dctrl & DEB_OPS) {
|
||
if (IS_29MB(u))
|
||
besm6_debug ("::: КМД %c: cmd %08o = выдача адреса дорожки %04o",
|
||
ctlr + '3', cmd, c->zone);
|
||
else
|
||
besm6_debug ("::: КМД %c: cmd %08o = выдача адреса дорожки %04o.%d",
|
||
ctlr + '3', cmd, c->zone, c->track);
|
||
}
|
||
disk_fail &= ~c->mask_fail;
|
||
if (c->op & DISK_READ) {
|
||
if (IS_29MB(u) || c->op & DISK_PAGE_MODE)
|
||
disk_read (u);
|
||
else
|
||
disk_read_track (u);
|
||
} else {
|
||
if (u->flags & UNIT_RO) {
|
||
/* Read only. */
|
||
/*longjmp (cpu_halt, SCPE_RO);*/
|
||
disk_fail |= c->mask_fail;
|
||
return;
|
||
}
|
||
if (c->format)
|
||
disk_format (u);
|
||
else if (IS_29MB(u) || c->op & DISK_PAGE_MODE)
|
||
disk_write (u);
|
||
else
|
||
disk_write_track (u);
|
||
}
|
||
|
||
/* Ждём события от устройства. */
|
||
sim_activate (u, 20*USEC); /* Ускорим для отладки. */
|
||
|
||
} else if (cmd & BBIT(11)) {
|
||
/* Выбора номера устройства и занесение в регистр маски КМД.
|
||
* Бит 8 - устройство 0, бит 7 - устройство 1, ... бит 1 - устройство 7.
|
||
* Также установлен бит 9 - что он означает? */
|
||
if (cmd & BBIT(8)) c->dev = 7;
|
||
else if (cmd & BBIT(7)) c->dev = 6;
|
||
else if (cmd & BBIT(6)) c->dev = 5;
|
||
else if (cmd & BBIT(5)) c->dev = 4;
|
||
else if (cmd & BBIT(4)) c->dev = 3;
|
||
else if (cmd & BBIT(3)) c->dev = 2;
|
||
else if (cmd & BBIT(2)) c->dev = 1;
|
||
else if (cmd & BBIT(1)) c->dev = 0;
|
||
else if (cmd != BBIT(11)) {
|
||
/* Неверная маска выбора устройства. */
|
||
c->dev = -1;
|
||
besm6_debug("Bad unit selection command %o", cmd);
|
||
return;
|
||
} else {
|
||
c->dev = -1;
|
||
return;
|
||
}
|
||
c->dev += ctlr * 32 + c->group * 8;
|
||
u = &md_unit [c->dev];
|
||
if (IS_29MB(u)) {
|
||
c->zone = (c->zone & ~1) | (cmd & BBIT(10) ? 1 : 0);
|
||
}
|
||
u = &md_unit[c->dev];
|
||
|
||
if (u->dptr->dctrl & DEB_OPS)
|
||
besm6_debug ("::: КМД %c: cmd = %08o, выбор устройства %02o",
|
||
ctlr + '3', cmd, c->dev);
|
||
|
||
if ((u->dptr->flags & DEV_DIS) || ! (u->flags & UNIT_ATT)) {
|
||
/* Device not attached. */
|
||
disk_fail |= c->mask_fail;
|
||
GRP &= ~c->mask_grp;
|
||
}
|
||
GRP |= c->mask_grp;
|
||
|
||
} else if (cmd & BBIT(9)) {
|
||
/* Group selection, LSB of track #, interrupt */
|
||
if ((cmd & 01774) == 01400) {
|
||
int prev = c->group;
|
||
c->group = cmd & 3;
|
||
c->dev = (c->dev & ~030) | (c->group << 3);
|
||
if (u->dptr->dctrl & DEB_OPS && c->group != prev)
|
||
besm6_debug ("::: КМД %c: selected group %d",
|
||
ctlr + '3', c->group);
|
||
}
|
||
GRP |= c->mask_grp;
|
||
} else if (cmd & BBIT(8)) {
|
||
besm6_debug ("::: КМД %c: cmd = %08o\n",
|
||
ctlr + '3', cmd);
|
||
|
||
} else {
|
||
/* Команда, выдаваемая в КМД. */
|
||
switch (cmd & 077) {
|
||
case 000: /* диспак выдаёт эту команду один раз в начале загрузки */
|
||
if (u->dptr->dctrl & DEB_OPS)
|
||
besm6_debug ("::: КМД %c: недокументированная команда %08o",
|
||
ctlr + '3', cmd);
|
||
break;
|
||
case 001: /* сброс на 0 цилиндр */
|
||
#if 1
|
||
if (u->dptr->dctrl & DEB_OPS)
|
||
besm6_debug ("::: КМД %c: сброс на 0 цилиндр",
|
||
ctlr + '3');
|
||
#endif
|
||
break;
|
||
case 002: /* подвод */
|
||
if (u->dptr->dctrl & DEB_OPS)
|
||
besm6_debug ("::: КМД %c: подвод", ctlr + '3');
|
||
break;
|
||
case 003: /* чтение (НСМД-МОЗУ) */
|
||
case 043: /* резервной дорожки */
|
||
#if 1
|
||
if (u->dptr->dctrl & DEB_OPS)
|
||
besm6_debug ("::: КМД %c: чтение", ctlr + '3');
|
||
#endif
|
||
break;
|
||
case 004: /* запись (МОЗУ-НСМД) */
|
||
case 044: /* резервной дорожки */
|
||
#if 1
|
||
if (u->dptr->dctrl & DEB_OPS)
|
||
besm6_debug ("::: КМД %c: запись", ctlr + '3');
|
||
#endif
|
||
break;
|
||
case 005: /* разметка */
|
||
c->format = 1;
|
||
break;
|
||
case 006: /* сравнение кодов (МОЗУ-НСМД) */
|
||
#if 1
|
||
if (u->dptr->dctrl & DEB_OPS)
|
||
besm6_debug ("::: КМД %c: сравнение кодов", ctlr + '3');
|
||
#endif
|
||
break;
|
||
case 007: /* чтение заголовка */
|
||
case 047: /* резервной дорожки */
|
||
if (u->dptr->dctrl & DEB_OPS)
|
||
besm6_debug ("::: КМД %c: чтение %s заголовка", ctlr + '3',
|
||
cmd & 040 ? "резервного" : "");
|
||
disk_fail &= ~c->mask_fail;
|
||
disk_read_header (u);
|
||
|
||
/* Ждём события от устройства. */
|
||
sim_activate (u, 20*USEC); /* Ускорим для отладки. */
|
||
break;
|
||
case 010: /* гашение PC */
|
||
#if 1
|
||
if (u->dptr->dctrl & DEB_OPS)
|
||
besm6_debug ("::: КМД %c: гашение регистра состояния",
|
||
ctlr + '3');
|
||
#endif
|
||
c->status = 0;
|
||
break;
|
||
case 011: /* опрос 1÷12 разрядов PC */
|
||
c->status = 0;
|
||
if (c->dev != -1 && md_unit[c->dev].flags & UNIT_ATT)
|
||
c->status = STATUS_READY;
|
||
#if 1
|
||
if (u->dptr->dctrl & DEB_STA)
|
||
besm6_debug ("::: КМД %c: опрос младших разрядов состояния - %04o",
|
||
ctlr + '3', c->status);
|
||
#endif
|
||
break;
|
||
case 031: /* опрос 13÷24 разрядов РС */
|
||
c->status = 0;
|
||
if (c->dev < 0 || md_unit[c->dev].flags & UNIT_DISABLE)
|
||
c->status |= STATUS_ABSENT;
|
||
else if (md_unit[c->dev].flags & UNIT_ATT)
|
||
c->status |= STATUS_POWERUP;
|
||
if (c->dev != -1 && md_unit[c->dev].flags & UNIT_RO)
|
||
c->status |= STATUS_READONLY;
|
||
c->status >>= 12;
|
||
#if 1
|
||
if (u->dptr->dctrl & DEB_STA)
|
||
besm6_debug ("::: КМД %c: опрос старших разрядов состояния - %04o",
|
||
ctlr + '3', c->status);
|
||
#endif
|
||
break;
|
||
case 050: /* освобождение НМД */
|
||
#if 1
|
||
if (u->dptr->dctrl & DEB_OPS)
|
||
besm6_debug ("::: КМД %c: освобождение накопителя",
|
||
ctlr + '3');
|
||
#endif
|
||
break;
|
||
default:
|
||
besm6_debug ("::: КМД %c: неизвестная команда %02o",
|
||
ctlr + '3', cmd & 077);
|
||
GRP |= c->mask_grp; /* чтобы не зависало */
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
/*
|
||
* Запрос состояния контроллера.
|
||
*/
|
||
int disk_state (int ctlr)
|
||
{
|
||
KMD *c = &controller [ctlr];
|
||
if (md_dev[ctlr*4].dctrl & DEB_RRD ||
|
||
md_dev[ctlr*4+1].dctrl & DEB_RRD ||
|
||
md_dev[ctlr*4+2].dctrl & DEB_RRD ||
|
||
md_dev[ctlr*4+3].dctrl & DEB_RRD)
|
||
besm6_debug ("::: КМД %c: опрос состояния = %04o",
|
||
ctlr + '3', c->status);
|
||
return c->status;
|
||
}
|
||
|
||
/*
|
||
* Событие: закончен обмен с МД.
|
||
* Устанавливаем флаг прерывания.
|
||
*/
|
||
t_stat disk_event (UNIT *u)
|
||
{
|
||
KMD *c = unit_to_ctlr (u);
|
||
|
||
GRP |= c->mask_grp;
|
||
return SCPE_OK;
|
||
}
|
||
|
||
/*
|
||
* Опрос ошибок обмена командой 033 4035.
|
||
*/
|
||
int disk_errors ()
|
||
{
|
||
#if 0
|
||
if (u->dptr->dctrl & DEB_RRD)
|
||
besm6_debug ("::: КМД: опрос шкалы ошибок = %04o", disk_fail);
|
||
#endif
|
||
return disk_fail;
|
||
}
|